makeform.c revision 100ae103
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 59100ae103Smrg for (i = 0; i < n; i++) { 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 94100ae103Smrg if (!buttonlist) return 0; 95100ae103Smrg 96100ae103Smrg /* 97100ae103Smrg * Figure out how many matches we will find so that we can preallocate 98100ae103Smrg * space for button structures. If you add stripping of white space, 99100ae103Smrg * make sure that you update this as well as the walking algorithm below. 100100ae103Smrg */ 101100ae103Smrg if (buttonlist[0]) shouldfind++; 102100ae103Smrg for (cp = buttonlist; *cp; cp++) { 103100ae103Smrg if (quoted == 1) quoted = 0; 104100ae103Smrg else if (*cp == '\\') quoted = 1; 105100ae103Smrg else if (*cp == ',') shouldfind++; 106100ae103Smrg } 107100ae103Smrg len = (cp - buttonlist); 108100ae103Smrg 109100ae103Smrg /* 110100ae103Smrg * allocate space for button record 111100ae103Smrg */ 112100ae103Smrg br = (ButtonRecord *) malloc (sizeof(ButtonRecord) * shouldfind); 113100ae103Smrg if (!br) return -1; 114100ae103Smrg 115100ae103Smrg cp = malloc (len + 1); 116100ae103Smrg if (!cp) { 117100ae103Smrg (void) free ((char *) br); 118100ae103Smrg return -1; 119100ae103Smrg } 120100ae103Smrg copy = cp; 121100ae103Smrg strcpy (copy, buttonlist); 122100ae103Smrg 123100ae103Smrg 124100ae103Smrg /* 125100ae103Smrg * walk down list separating into name:exitcode pairs 126100ae103Smrg */ 127100ae103Smrg while (*cp) { 128100ae103Smrg char *start, *colon, *comma; 129100ae103Smrg int exitcode; 130100ae103Smrg 131100ae103Smrg start = cp; 132100ae103Smrg colon = comma = NULL; 133100ae103Smrg exitcode = ++default_exitcode; 134100ae103Smrg quoted = 0; 135100ae103Smrg 136100ae103Smrg /* find the next name and exit code */ 137100ae103Smrg for (; *cp; cp++) { 138100ae103Smrg if (quoted) quoted = 0; 139100ae103Smrg else if (*cp == '\\') quoted = 1; 140100ae103Smrg else if (*cp == ':') colon = cp; 141100ae103Smrg else if (*cp == ',') { 142100ae103Smrg comma = cp; 143100ae103Smrg break; 144100ae103Smrg } 145100ae103Smrg } 146100ae103Smrg 147100ae103Smrg /* 148100ae103Smrg * If comma is NULL then we are at the end of the string. If colon 149100ae103Smrg * is NULL, then there was no exit code given, so default to zero. 150100ae103Smrg */ 151100ae103Smrg 152100ae103Smrg if (comma) *comma = '\0'; 153100ae103Smrg 154100ae103Smrg if (colon) { 155100ae103Smrg exitcode = atoi (colon+1); 156100ae103Smrg *colon = '\0'; 157100ae103Smrg } 158100ae103Smrg 159100ae103Smrg /* 160100ae103Smrg * make sure that we aren't about to stomp on memory 161100ae103Smrg */ 162100ae103Smrg if (npairs >= shouldfind) { 163100ae103Smrg fprintf (stderr, 164100ae103Smrg "%s: internal error, found extra pairs (should be %d)\n", 165100ae103Smrg ProgramName, shouldfind); 166100ae103Smrg (void) free ((char *) br); 167100ae103Smrg (void) free (copy); 168100ae103Smrg return -1; 169100ae103Smrg } 170100ae103Smrg 171100ae103Smrg /* 172100ae103Smrg * got it! start and exitcode contain the right values 173100ae103Smrg */ 174100ae103Smrg br[npairs].name = start; 175100ae103Smrg br[npairs].exitstatus = exitcode; 176100ae103Smrg npairs++; 177100ae103Smrg 178100ae103Smrg if (comma) cp++; 179100ae103Smrg } 180100ae103Smrg 181100ae103Smrg 182100ae103Smrg if (npairs != shouldfind) { 183100ae103Smrg fprintf (stderr, "%s: internal error found %d instead of %d pairs\n", 184100ae103Smrg ProgramName, npairs, shouldfind); 185100ae103Smrg (void) free ((char *) br); 186100ae103Smrg (void) free (copy); 187100ae103Smrg return -1; 188100ae103Smrg } 189100ae103Smrg 190100ae103Smrg /* 191100ae103Smrg * now, strip any quoted characters 192100ae103Smrg */ 193100ae103Smrg unquote_pairs (br, npairs); 194100ae103Smrg *brptr = br; 195100ae103Smrg return npairs; 196100ae103Smrg} 197100ae103Smrg 198100ae103Smrg/* ARGSUSED */ 199100ae103Smrgstatic void 200100ae103Smrghandle_button (Widget w, XtPointer closure, XtPointer client_data) 201100ae103Smrg{ 202100ae103Smrg ButtonRecord *br = (ButtonRecord *) closure; 203100ae103Smrg 204100ae103Smrg if (br->print_value) 205100ae103Smrg puts (br->name); 206100ae103Smrg exit (br->exitstatus); 207100ae103Smrg} 208100ae103Smrg 209100ae103SmrgWidget 210100ae103Smrgmake_queryform(Widget parent, /* into whom widget should be placed */ 211100ae103Smrg char *msgstr, /* message string */ 212100ae103Smrg int msglen, /* characters in msgstr */ 213100ae103Smrg char *button_list, /* list of button title:status */ 214100ae103Smrg Boolean print_value, /* print button string on stdout? */ 215100ae103Smrg char *default_button, /* button activated by Return */ 216100ae103Smrg Dimension max_width, 217100ae103Smrg Dimension max_height) 218100ae103Smrg{ 219100ae103Smrg ButtonRecord *br; 220100ae103Smrg int npairs, i; 221100ae103Smrg Widget form, text, prev; 222100ae103Smrg Arg args[10]; 223100ae103Smrg Cardinal n, thisn; 224100ae103Smrg char *shell_geom; 225100ae103Smrg int x, y, geom_flags; 226100ae103Smrg unsigned int shell_w, shell_h; 227100ae103Smrg 228100ae103Smrg npairs = parse_name_and_exit_code_list (button_list, &br); 229100ae103Smrg 230100ae103Smrg form = XtCreateManagedWidget ("form", formWidgetClass, parent, NULL, 0); 231100ae103Smrg 232100ae103Smrg text = XtVaCreateManagedWidget 233100ae103Smrg ("message", asciiTextWidgetClass, form, 234100ae103Smrg XtNleft, XtChainLeft, 235100ae103Smrg XtNright, XtChainRight, 236100ae103Smrg XtNtop, XtChainTop, 237100ae103Smrg XtNbottom, XtChainBottom, 238100ae103Smrg XtNdisplayCaret, False, 239100ae103Smrg XtNlength, msglen, 240100ae103Smrg XtNstring, msgstr, 241100ae103Smrg NULL); 242100ae103Smrg /* 243100ae103Smrg * Did the user specify our geometry? 244100ae103Smrg * If so, don't bother computing it ourselves, since we will be overridden. 245100ae103Smrg */ 246100ae103Smrg XtVaGetValues(parent, XtNgeometry, &shell_geom, NULL); 247100ae103Smrg geom_flags = XParseGeometry(shell_geom, &x, &y, &shell_w, &shell_h); 248100ae103Smrg if (!(geom_flags & WidthValue && geom_flags & HeightValue)) { 249100ae103Smrg Dimension width, height, height_addons = 0; 250100ae103Smrg Dimension scroll_size, border_width; 251100ae103Smrg Widget label, scroll; 252100ae103Smrg Position left, right, top, bottom; 253100ae103Smrg char *tmp; 254100ae103Smrg /* 255100ae103Smrg * A Text widget is used for the automatic scroll bars. 256100ae103Smrg * But Text widget doesn't automatically compute its size. 257100ae103Smrg * The Label widget does that nicely, so we create one and examine it. 258100ae103Smrg * This widget is never visible. 259100ae103Smrg */ 260100ae103Smrg XtVaGetValues(text, XtNtopMargin, &top, XtNbottomMargin, &bottom, 261100ae103Smrg XtNleftMargin, &left, XtNrightMargin, &right, NULL); 262100ae103Smrg label = XtVaCreateWidget("message", labelWidgetClass, form, 263100ae103Smrg XtNlabel, msgstr, 264100ae103Smrg XtNinternalWidth, (left+right+1)/2, 265100ae103Smrg XtNinternalHeight, (top+bottom+1)/2, 266100ae103Smrg NULL); 267100ae103Smrg XtVaGetValues(label, XtNwidth, &width, XtNheight, &height, NULL); 268100ae103Smrg XtDestroyWidget(label); 269100ae103Smrg if (max_width == 0) 270100ae103Smrg max_width = .7 * WidthOfScreen(XtScreen(text)); 271100ae103Smrg if (max_height == 0) 272100ae103Smrg max_height = .7 * HeightOfScreen(XtScreen(text)); 273100ae103Smrg if (width > max_width) { 274100ae103Smrg width = max_width; 275100ae103Smrg /* add in the height of any horizontal scroll bar */ 276100ae103Smrg scroll = XtVaCreateWidget("hScrollbar", scrollbarWidgetClass, text, 277100ae103Smrg XtNorientation, XtorientHorizontal, 278100ae103Smrg NULL); 279100ae103Smrg XtVaGetValues(scroll, XtNheight, &scroll_size, 280100ae103Smrg XtNborderWidth, &border_width, NULL); 281100ae103Smrg XtDestroyWidget(scroll); 282100ae103Smrg height_addons = scroll_size + border_width; 283100ae103Smrg } 284100ae103Smrg 285100ae103Smrg /* This fixes the xmessage assumption that the label widget and the 286100ae103Smrg * text widget have the same size. In Xaw 7, the text widget has 287100ae103Smrg * one extra pixel between lines. 288100ae103Smrg * Xmessage is not internationalized, so the code bellow is harmless. 289100ae103Smrg */ 290100ae103Smrg tmp = msgstr; 291100ae103Smrg while (tmp != NULL && *tmp) { 292100ae103Smrg ++tmp; 293100ae103Smrg ++height; 294100ae103Smrg tmp = strchr(tmp, '\n'); 295100ae103Smrg } 296100ae103Smrg 297100ae103Smrg if (height > max_height) { 298100ae103Smrg height = max_height; 299100ae103Smrg /* add in the width of any vertical scroll bar */ 300100ae103Smrg scroll = XtVaCreateWidget("vScrollbar", scrollbarWidgetClass, text, 301100ae103Smrg XtNorientation, XtorientVertical, NULL); 302100ae103Smrg XtVaGetValues(scroll, XtNwidth, &scroll_size, 303100ae103Smrg XtNborderWidth, &border_width, NULL); 304100ae103Smrg XtDestroyWidget(scroll); 305100ae103Smrg width += scroll_size + border_width; 306100ae103Smrg } 307100ae103Smrg height += height_addons; 308100ae103Smrg XtVaSetValues(text, XtNwidth, width, XtNheight, height, NULL); 309100ae103Smrg } 310100ae103Smrg /* 311100ae103Smrg * Create the buttons 312100ae103Smrg */ 313100ae103Smrg n = 0; 314100ae103Smrg XtSetArg (args[n], XtNleft, XtChainLeft); n++; 315100ae103Smrg XtSetArg (args[n], XtNright, XtChainLeft); n++; 316100ae103Smrg XtSetArg (args[n], XtNtop, XtChainBottom); n++; 317100ae103Smrg XtSetArg (args[n], XtNbottom, XtChainBottom); n++; 318100ae103Smrg XtSetArg (args[n], XtNfromVert, text); n++; 319100ae103Smrg XtSetArg (args[n], XtNvertDistance, 5); n++; 320100ae103Smrg 321100ae103Smrg prev = NULL; 322100ae103Smrg for (i = 0; i < npairs; i++) { 323100ae103Smrg thisn = n; 324100ae103Smrg XtSetArg (args[thisn], XtNfromHoriz, prev); thisn++; 325100ae103Smrg prev = XtCreateManagedWidget (br[i].name, commandWidgetClass, 326100ae103Smrg form, args, thisn); 327100ae103Smrg br[i].widget = prev; 328100ae103Smrg br[i].print_value = print_value; 329100ae103Smrg XtAddCallback (prev, XtNcallback, handle_button, (XtPointer) &br[i]); 330100ae103Smrg if (default_button && !strcmp(default_button, br[i].name)) { 331100ae103Smrg Dimension border; 332100ae103Smrg 333100ae103Smrg default_exitstatus = br[i].exitstatus; 334100ae103Smrg XtVaGetValues(br[i].widget, XtNborderWidth, &border, NULL); 335100ae103Smrg border *= 2; 336100ae103Smrg XtVaSetValues(br[i].widget, XtNborderWidth, border, NULL); 337100ae103Smrg } 338100ae103Smrg } 339100ae103Smrg return form; 340100ae103Smrg} 341