1100ae103Smrg/* $XConsortium: makeform.c,v 1.6 95/01/04 16:28:51 gildea Exp $ */ 2100ae103Smrg/* 3100ae103Smrg 4100ae103SmrgCopyright (c) 1988, 1991 X Consortium 5100ae103Smrg 6100ae103SmrgPermission is hereby granted, free of charge, to any person obtaining 7100ae103Smrga copy of this software and associated documentation files (the 8100ae103Smrg"Software"), to deal in the Software without restriction, including 9100ae103Smrgwithout limitation the rights to use, copy, modify, merge, publish, 10100ae103Smrgdistribute, sublicense, and/or sell copies of the Software, and to 11100ae103Smrgpermit persons to whom the Software is furnished to do so, subject to 12100ae103Smrgthe following conditions: 13100ae103Smrg 14100ae103SmrgThe above copyright notice and this permission notice shall be included 15100ae103Smrgin all copies or substantial portions of the Software. 16100ae103Smrg 17100ae103SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18100ae103SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19100ae103SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20100ae103SmrgIN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 21100ae103SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22100ae103SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23100ae103SmrgOTHER DEALINGS IN THE SOFTWARE. 24100ae103Smrg 25100ae103SmrgExcept as contained in this notice, the name of the X Consortium shall 26100ae103Smrgnot be used in advertising or otherwise to promote the sale, use or 27100ae103Smrgother dealings in this Software without prior written authorization 28100ae103Smrgfrom the X Consortium. 29100ae103Smrg 30100ae103Smrg*/ 31100ae103Smrg/* $XFree86: xc/programs/xmessage/makeform.c,v 1.6 2002/11/22 03:56:39 paulo Exp $ */ 32100ae103Smrg 33100ae103Smrg#include <X11/Intrinsic.h> 34100ae103Smrg#include <X11/StringDefs.h> 35100ae103Smrg#include <stdio.h> 36100ae103Smrg#include <stdlib.h> 37100ae103Smrg 38100ae103Smrg#include <X11/Shell.h> 39100ae103Smrg#include <X11/Xaw/Form.h> 40100ae103Smrg#include <X11/Xaw/AsciiText.h> 41100ae103Smrg#include <X11/Xaw/Command.h> 42100ae103Smrg#include <X11/Xaw/Label.h> 43100ae103Smrg#include <X11/Xaw/Scrollbar.h> 44100ae103Smrg 45100ae103Smrg#include "xmessage.h" 46100ae103Smrg 47100ae103Smrgtypedef struct _ButtonRecord { 48100ae103Smrg char *name; 49100ae103Smrg int exitstatus; 50100ae103Smrg Boolean print_value; 51100ae103Smrg Widget widget; 52100ae103Smrg} ButtonRecord; 53100ae103Smrg 54100ae103Smrgstatic void 55100ae103Smrgunquote_pairs (ButtonRecord *br, int n) 56100ae103Smrg{ 57100ae103Smrg int i; 58100ae103Smrg 59165cb819Smrg for (i = 0; i < n; i++, br++) { 60100ae103Smrg char *dst, *src; 61100ae103Smrg int quoted = 0; 62100ae103Smrg 63100ae103Smrg for (src = dst = br->name; *src; src++) { 64100ae103Smrg if (quoted) { 65100ae103Smrg *dst++ = *src; 66100ae103Smrg quoted = 0; 67100ae103Smrg } else if (src[0] == '\\') { 68100ae103Smrg quoted = 1; 69100ae103Smrg } else { 70100ae103Smrg *dst++ = *src; 71100ae103Smrg } 72100ae103Smrg } 73100ae103Smrg *dst = '\0'; 74100ae103Smrg } 75100ae103Smrg return; 76100ae103Smrg} 77100ae103Smrg 78100ae103Smrg/* 79100ae103Smrg * parses string of form "yes:11,no:12, ..." 80100ae103Smrg * sets brptr to point to parsed table 81100ae103Smrg * returns 0 if successful, -1 if not 82100ae103Smrg */ 83100ae103Smrgstatic int 84100ae103Smrgparse_name_and_exit_code_list (char *buttonlist, ButtonRecord **brptr) 85100ae103Smrg{ 86100ae103Smrg char *cp; 87100ae103Smrg int shouldfind = 0, npairs = 0; 88100ae103Smrg int default_exitcode = 100; 89100ae103Smrg int quoted = 0; 90100ae103Smrg ButtonRecord *br; 91100ae103Smrg int len; 92100ae103Smrg char *copy; 93100ae103Smrg 94165cb819Smrg *brptr = NULL; 95100ae103Smrg if (!buttonlist) return 0; 96100ae103Smrg 97100ae103Smrg /* 98100ae103Smrg * Figure out how many matches we will find so that we can preallocate 99100ae103Smrg * space for button structures. If you add stripping of white space, 100100ae103Smrg * make sure that you update this as well as the walking algorithm below. 101100ae103Smrg */ 102100ae103Smrg if (buttonlist[0]) shouldfind++; 103100ae103Smrg for (cp = buttonlist; *cp; cp++) { 104100ae103Smrg if (quoted == 1) quoted = 0; 105100ae103Smrg else if (*cp == '\\') quoted = 1; 106100ae103Smrg else if (*cp == ',') shouldfind++; 107100ae103Smrg } 108100ae103Smrg len = (cp - buttonlist); 109100ae103Smrg 110100ae103Smrg /* 111100ae103Smrg * allocate space for button record 112100ae103Smrg */ 113100ae103Smrg br = (ButtonRecord *) malloc (sizeof(ButtonRecord) * shouldfind); 114100ae103Smrg if (!br) return -1; 115100ae103Smrg 116100ae103Smrg cp = malloc (len + 1); 117100ae103Smrg if (!cp) { 1180103645bSmrg free (br); 119100ae103Smrg return -1; 120100ae103Smrg } 121100ae103Smrg copy = cp; 122100ae103Smrg strcpy (copy, buttonlist); 123100ae103Smrg 124100ae103Smrg 125100ae103Smrg /* 126100ae103Smrg * walk down list separating into name:exitcode pairs 127100ae103Smrg */ 128100ae103Smrg while (*cp) { 129100ae103Smrg char *start, *colon, *comma; 130100ae103Smrg int exitcode; 131100ae103Smrg 132100ae103Smrg start = cp; 133100ae103Smrg colon = comma = NULL; 134100ae103Smrg exitcode = ++default_exitcode; 135100ae103Smrg quoted = 0; 136100ae103Smrg 137100ae103Smrg /* find the next name and exit code */ 138100ae103Smrg for (; *cp; cp++) { 139100ae103Smrg if (quoted) quoted = 0; 140100ae103Smrg else if (*cp == '\\') quoted = 1; 141100ae103Smrg else if (*cp == ':') colon = cp; 142100ae103Smrg else if (*cp == ',') { 143100ae103Smrg comma = cp; 144100ae103Smrg break; 145100ae103Smrg } 146100ae103Smrg } 147100ae103Smrg 148100ae103Smrg /* 149100ae103Smrg * If comma is NULL then we are at the end of the string. If colon 150100ae103Smrg * is NULL, then there was no exit code given, so default to zero. 151100ae103Smrg */ 152100ae103Smrg 153100ae103Smrg if (comma) *comma = '\0'; 154100ae103Smrg 155100ae103Smrg if (colon) { 156100ae103Smrg exitcode = atoi (colon+1); 157100ae103Smrg *colon = '\0'; 158100ae103Smrg } 159100ae103Smrg 160100ae103Smrg /* 161100ae103Smrg * make sure that we aren't about to stomp on memory 162100ae103Smrg */ 163100ae103Smrg if (npairs >= shouldfind) { 164100ae103Smrg fprintf (stderr, 165100ae103Smrg "%s: internal error, found extra pairs (should be %d)\n", 166100ae103Smrg ProgramName, shouldfind); 1670103645bSmrg free (br); 1680103645bSmrg free (copy); 169100ae103Smrg return -1; 170100ae103Smrg } 171100ae103Smrg 172100ae103Smrg /* 173100ae103Smrg * got it! start and exitcode contain the right values 174100ae103Smrg */ 175100ae103Smrg br[npairs].name = start; 176100ae103Smrg br[npairs].exitstatus = exitcode; 177100ae103Smrg npairs++; 178100ae103Smrg 179100ae103Smrg if (comma) cp++; 180100ae103Smrg } 181100ae103Smrg 182100ae103Smrg 183100ae103Smrg if (npairs != shouldfind) { 184100ae103Smrg fprintf (stderr, "%s: internal error found %d instead of %d pairs\n", 185100ae103Smrg ProgramName, npairs, shouldfind); 1860103645bSmrg free (br); 1870103645bSmrg free (copy); 188100ae103Smrg return -1; 189100ae103Smrg } 190100ae103Smrg 191100ae103Smrg /* 192100ae103Smrg * now, strip any quoted characters 193100ae103Smrg */ 194100ae103Smrg unquote_pairs (br, npairs); 195100ae103Smrg *brptr = br; 196100ae103Smrg return npairs; 197100ae103Smrg} 198100ae103Smrg 199100ae103Smrg/* ARGSUSED */ 200100ae103Smrgstatic void 201100ae103Smrghandle_button (Widget w, XtPointer closure, XtPointer client_data) 202100ae103Smrg{ 203100ae103Smrg ButtonRecord *br = (ButtonRecord *) closure; 204100ae103Smrg 205100ae103Smrg if (br->print_value) 206100ae103Smrg puts (br->name); 207100ae103Smrg exit (br->exitstatus); 208100ae103Smrg} 209100ae103Smrg 210100ae103SmrgWidget 211100ae103Smrgmake_queryform(Widget parent, /* into whom widget should be placed */ 212100ae103Smrg char *msgstr, /* message string */ 213100ae103Smrg int msglen, /* characters in msgstr */ 214100ae103Smrg char *button_list, /* list of button title:status */ 215100ae103Smrg Boolean print_value, /* print button string on stdout? */ 216100ae103Smrg char *default_button, /* button activated by Return */ 217100ae103Smrg Dimension max_width, 218100ae103Smrg Dimension max_height) 219100ae103Smrg{ 220100ae103Smrg ButtonRecord *br; 221100ae103Smrg int npairs, i; 222100ae103Smrg Widget form, text, prev; 223100ae103Smrg Arg args[10]; 224100ae103Smrg Cardinal n, thisn; 225100ae103Smrg char *shell_geom; 226100ae103Smrg int x, y, geom_flags; 227100ae103Smrg unsigned int shell_w, shell_h; 228100ae103Smrg 229100ae103Smrg npairs = parse_name_and_exit_code_list (button_list, &br); 230100ae103Smrg 231100ae103Smrg form = XtCreateManagedWidget ("form", formWidgetClass, parent, NULL, 0); 232100ae103Smrg 233100ae103Smrg text = XtVaCreateManagedWidget 234100ae103Smrg ("message", asciiTextWidgetClass, form, 235100ae103Smrg XtNleft, XtChainLeft, 236100ae103Smrg XtNright, XtChainRight, 237100ae103Smrg XtNtop, XtChainTop, 238100ae103Smrg XtNbottom, XtChainBottom, 239100ae103Smrg XtNdisplayCaret, False, 240100ae103Smrg XtNlength, msglen, 241100ae103Smrg XtNstring, msgstr, 242100ae103Smrg NULL); 243100ae103Smrg /* 244100ae103Smrg * Did the user specify our geometry? 245100ae103Smrg * If so, don't bother computing it ourselves, since we will be overridden. 246100ae103Smrg */ 247100ae103Smrg XtVaGetValues(parent, XtNgeometry, &shell_geom, NULL); 248100ae103Smrg geom_flags = XParseGeometry(shell_geom, &x, &y, &shell_w, &shell_h); 249100ae103Smrg if (!(geom_flags & WidthValue && geom_flags & HeightValue)) { 250100ae103Smrg Dimension width, height, height_addons = 0; 251100ae103Smrg Dimension scroll_size, border_width; 252100ae103Smrg Widget label, scroll; 253100ae103Smrg Position left, right, top, bottom; 254100ae103Smrg char *tmp; 255100ae103Smrg /* 256100ae103Smrg * A Text widget is used for the automatic scroll bars. 257100ae103Smrg * But Text widget doesn't automatically compute its size. 258100ae103Smrg * The Label widget does that nicely, so we create one and examine it. 259100ae103Smrg * This widget is never visible. 260100ae103Smrg */ 261100ae103Smrg XtVaGetValues(text, XtNtopMargin, &top, XtNbottomMargin, &bottom, 262100ae103Smrg XtNleftMargin, &left, XtNrightMargin, &right, NULL); 263100ae103Smrg label = XtVaCreateWidget("message", labelWidgetClass, form, 264100ae103Smrg XtNlabel, msgstr, 265100ae103Smrg XtNinternalWidth, (left+right+1)/2, 266100ae103Smrg XtNinternalHeight, (top+bottom+1)/2, 267100ae103Smrg NULL); 268100ae103Smrg XtVaGetValues(label, XtNwidth, &width, XtNheight, &height, NULL); 269100ae103Smrg XtDestroyWidget(label); 270100ae103Smrg if (max_width == 0) 271100ae103Smrg max_width = .7 * WidthOfScreen(XtScreen(text)); 272100ae103Smrg if (max_height == 0) 273100ae103Smrg max_height = .7 * HeightOfScreen(XtScreen(text)); 274100ae103Smrg if (width > max_width) { 275100ae103Smrg width = max_width; 276100ae103Smrg /* add in the height of any horizontal scroll bar */ 277100ae103Smrg scroll = XtVaCreateWidget("hScrollbar", scrollbarWidgetClass, text, 278100ae103Smrg XtNorientation, XtorientHorizontal, 279100ae103Smrg NULL); 280100ae103Smrg XtVaGetValues(scroll, XtNheight, &scroll_size, 281100ae103Smrg XtNborderWidth, &border_width, NULL); 282100ae103Smrg XtDestroyWidget(scroll); 283100ae103Smrg height_addons = scroll_size + border_width; 284100ae103Smrg } 285100ae103Smrg 286100ae103Smrg /* This fixes the xmessage assumption that the label widget and the 287100ae103Smrg * text widget have the same size. In Xaw 7, the text widget has 288100ae103Smrg * one extra pixel between lines. 289100ae103Smrg * Xmessage is not internationalized, so the code bellow is harmless. 290100ae103Smrg */ 291100ae103Smrg tmp = msgstr; 292100ae103Smrg while (tmp != NULL && *tmp) { 293100ae103Smrg ++tmp; 294100ae103Smrg ++height; 295100ae103Smrg tmp = strchr(tmp, '\n'); 296100ae103Smrg } 297100ae103Smrg 298100ae103Smrg if (height > max_height) { 299100ae103Smrg height = max_height; 300100ae103Smrg /* add in the width of any vertical scroll bar */ 301100ae103Smrg scroll = XtVaCreateWidget("vScrollbar", scrollbarWidgetClass, text, 302100ae103Smrg XtNorientation, XtorientVertical, NULL); 303100ae103Smrg XtVaGetValues(scroll, XtNwidth, &scroll_size, 304100ae103Smrg XtNborderWidth, &border_width, NULL); 305100ae103Smrg XtDestroyWidget(scroll); 306100ae103Smrg width += scroll_size + border_width; 307100ae103Smrg } 308100ae103Smrg height += height_addons; 309100ae103Smrg XtVaSetValues(text, XtNwidth, width, XtNheight, height, NULL); 310100ae103Smrg } 311100ae103Smrg /* 312100ae103Smrg * Create the buttons 313100ae103Smrg */ 314100ae103Smrg n = 0; 315100ae103Smrg XtSetArg (args[n], XtNleft, XtChainLeft); n++; 316100ae103Smrg XtSetArg (args[n], XtNright, XtChainLeft); n++; 317100ae103Smrg XtSetArg (args[n], XtNtop, XtChainBottom); n++; 318100ae103Smrg XtSetArg (args[n], XtNbottom, XtChainBottom); n++; 319100ae103Smrg XtSetArg (args[n], XtNfromVert, text); n++; 320100ae103Smrg XtSetArg (args[n], XtNvertDistance, 5); n++; 321100ae103Smrg 322100ae103Smrg prev = NULL; 323100ae103Smrg for (i = 0; i < npairs; i++) { 324100ae103Smrg thisn = n; 325100ae103Smrg XtSetArg (args[thisn], XtNfromHoriz, prev); thisn++; 326100ae103Smrg prev = XtCreateManagedWidget (br[i].name, commandWidgetClass, 327100ae103Smrg form, args, thisn); 328100ae103Smrg br[i].widget = prev; 329100ae103Smrg br[i].print_value = print_value; 330100ae103Smrg XtAddCallback (prev, XtNcallback, handle_button, (XtPointer) &br[i]); 331100ae103Smrg if (default_button && !strcmp(default_button, br[i].name)) { 332100ae103Smrg Dimension border; 333100ae103Smrg 334100ae103Smrg default_exitstatus = br[i].exitstatus; 335100ae103Smrg XtVaGetValues(br[i].widget, XtNborderWidth, &border, NULL); 336100ae103Smrg border *= 2; 337100ae103Smrg XtVaSetValues(br[i].widget, XtNborderWidth, border, NULL); 338100ae103Smrg } 339100ae103Smrg } 340100ae103Smrg return form; 341100ae103Smrg} 342