diff options
Diffstat (limited to 'makeform.c')
-rw-r--r-- | makeform.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/makeform.c b/makeform.c new file mode 100644 index 0000000..3820ebb --- /dev/null +++ b/makeform.c @@ -0,0 +1,347 @@ +/* $XConsortium: makeform.c,v 1.6 95/01/04 16:28:51 gildea Exp $ */ +/* + +Copyright (c) 1988, 1991 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the X Consortium. + +*/ +/* $XFree86: xc/programs/xmessage/makeform.c,v 1.6 2002/11/22 03:56:39 paulo Exp $ */ + +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <stdio.h> +#include <stdlib.h> + +#include <X11/Shell.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/AsciiText.h> +#include <X11/Xaw/Command.h> +#include <X11/Xaw/Label.h> +#include <X11/Xaw/Scrollbar.h> + +extern const char *ProgramName; +extern int default_exitstatus; + +typedef struct _ButtonRecord { + char *name; + int exitstatus; + Boolean print_value; + Widget widget; +} ButtonRecord; + +static void unquote_pairs (br, n) + register ButtonRecord *br; + int n; +{ + int i; + + for (i = 0; i < n; i++) { + register char *dst, *src; + register int quoted = 0; + + for (src = dst = br->name; *src; src++) { + if (quoted) { + *dst++ = *src; + quoted = 0; + } else if (src[0] == '\\') { + quoted = 1; + } else { + *dst++ = *src; + } + } + *dst = '\0'; + } + return; +} + +/* + * parses string of form "yes:11,no:12, ..." + * sets brptr to point to parsed table + * returns 0 if successful, -1 if not + */ +static int parse_name_and_exit_code_list (buttonlist, brptr) + char *buttonlist; + ButtonRecord **brptr; +{ + register char *cp; + int shouldfind = 0, npairs = 0; + int default_exitcode = 100; + int quoted = 0; + ButtonRecord *br; + int len; + char *copy; + + if (!buttonlist) return 0; + + /* + * Figure out how many matches we will find so that we can preallocate + * space for button structures. If you add stripping of white space, + * make sure that you update this as well as the walking algorithm below. + */ + if (buttonlist[0]) shouldfind++; + for (cp = buttonlist; *cp; cp++) { + if (quoted == 1) quoted = 0; + else if (*cp == '\\') quoted = 1; + else if (*cp == ',') shouldfind++; + } + len = (cp - buttonlist); + + /* + * allocate space for button record + */ + br = (ButtonRecord *) malloc (sizeof(ButtonRecord) * shouldfind); + if (!br) return -1; + + cp = malloc (len + 1); + if (!cp) { + (void) free ((char *) br); + return -1; + } + copy = cp; + strcpy (copy, buttonlist); + + + /* + * walk down list separating into name:exitcode pairs + */ + while (*cp) { + char *start, *colon, *comma; + int exitcode; + + start = cp; + colon = comma = NULL; + exitcode = ++default_exitcode; + quoted = 0; + + /* find the next name and exit code */ + for (; *cp; cp++) { + if (quoted) quoted = 0; + else if (*cp == '\\') quoted = 1; + else if (*cp == ':') colon = cp; + else if (*cp == ',') { + comma = cp; + break; + } + } + + /* + * If comma is NULL then we are at the end of the string. If colon + * is NULL, then there was no exit code given, so default to zero. + */ + + if (comma) *comma = '\0'; + + if (colon) { + exitcode = atoi (colon+1); + *colon = '\0'; + } + + /* + * make sure that we aren't about to stomp on memory + */ + if (npairs >= shouldfind) { + fprintf (stderr, + "%s: internal error, found extra pairs (should be %d)\n", + ProgramName, shouldfind); + (void) free ((char *) br); + (void) free (copy); + return -1; + } + + /* + * got it! start and exitcode contain the right values + */ + br[npairs].name = start; + br[npairs].exitstatus = exitcode; + npairs++; + + if (comma) cp++; + } + + + if (npairs != shouldfind) { + fprintf (stderr, "%s: internal error found %d instead of %d pairs\n", + ProgramName, npairs, shouldfind); + (void) free ((char *) br); + (void) free (copy); + return -1; + } + + /* + * now, strip any quoted characters + */ + unquote_pairs (br, npairs); + *brptr = br; + return npairs; +} + +/* ARGSUSED */ +static void handle_button (w, closure, client_data) + Widget w; + XtPointer closure; + XtPointer client_data; +{ + ButtonRecord *br = (ButtonRecord *) closure; + + if (br->print_value) + puts (br->name); + exit (br->exitstatus); +} + +Widget make_queryform(parent, msgstr, msglen, + button_list, print_value, default_button, + max_width, max_height) + Widget parent; /* into whom widget should be placed */ + char *msgstr; /* message string */ + int msglen; /* characters in msgstr */ + char *button_list; /* list of button title:status */ + Boolean print_value; /* print button string on stdout? */ + char *default_button; /* button activated by Return */ + Dimension max_width; + Dimension max_height; +{ + ButtonRecord *br; + int npairs, i; + Widget form, text, prev; + Arg args[10]; + Cardinal n, thisn; + char *shell_geom; + int x, y, geom_flags; + unsigned int shell_w, shell_h; + + npairs = parse_name_and_exit_code_list (button_list, &br); + + form = XtCreateManagedWidget ("form", formWidgetClass, parent, NULL, 0); + + text = XtVaCreateManagedWidget + ("message", asciiTextWidgetClass, form, + XtNleft, XtChainLeft, + XtNright, XtChainRight, + XtNtop, XtChainTop, + XtNbottom, XtChainBottom, + XtNdisplayCaret, False, + XtNlength, msglen, + XtNstring, msgstr, + NULL); + /* + * Did the user specify our geometry? + * If so, don't bother computing it ourselves, since we will be overridden. + */ + XtVaGetValues(parent, XtNgeometry, &shell_geom, NULL); + geom_flags = XParseGeometry(shell_geom, &x, &y, &shell_w, &shell_h); + if (!(geom_flags & WidthValue && geom_flags & HeightValue)) { + Dimension width, height, height_addons = 0; + Dimension scroll_size, border_width; + Widget label, scroll; + Position left, right, top, bottom; + char *tmp; + /* + * A Text widget is used for the automatic scroll bars. + * But Text widget doesn't automatically compute its size. + * The Label widget does that nicely, so we create one and examine it. + * This widget is never visible. + */ + XtVaGetValues(text, XtNtopMargin, &top, XtNbottomMargin, &bottom, + XtNleftMargin, &left, XtNrightMargin, &right, NULL); + label = XtVaCreateWidget("message", labelWidgetClass, form, + XtNlabel, msgstr, + XtNinternalWidth, (left+right+1)/2, + XtNinternalHeight, (top+bottom+1)/2, + NULL); + XtVaGetValues(label, XtNwidth, &width, XtNheight, &height, NULL); + XtDestroyWidget(label); + if (max_width == 0) + max_width = .7 * WidthOfScreen(XtScreen(text)); + if (max_height == 0) + max_height = .7 * HeightOfScreen(XtScreen(text)); + if (width > max_width) { + width = max_width; + /* add in the height of any horizontal scroll bar */ + scroll = XtVaCreateWidget("hScrollbar", scrollbarWidgetClass, text, + XtNorientation, XtorientHorizontal, + NULL); + XtVaGetValues(scroll, XtNheight, &scroll_size, + XtNborderWidth, &border_width, NULL); + XtDestroyWidget(scroll); + height_addons = scroll_size + border_width; + } + + /* This fixes the xmessage assumption that the label widget and the + * text widget have the same size. In Xaw 7, the text widget has + * one extra pixel between lines. + * Xmessage is not internationalized, so the code bellow is harmless. + */ + tmp = msgstr; + while (tmp != NULL && *tmp) { + ++tmp; + ++height; + tmp = strchr(tmp, '\n'); + } + + if (height > max_height) { + height = max_height; + /* add in the width of any vertical scroll bar */ + scroll = XtVaCreateWidget("vScrollbar", scrollbarWidgetClass, text, + XtNorientation, XtorientVertical, NULL); + XtVaGetValues(scroll, XtNwidth, &scroll_size, + XtNborderWidth, &border_width, NULL); + XtDestroyWidget(scroll); + width += scroll_size + border_width; + } + height += height_addons; + XtVaSetValues(text, XtNwidth, width, XtNheight, height, NULL); + } + /* + * Create the buttons + */ + n = 0; + XtSetArg (args[n], XtNleft, XtChainLeft); n++; + XtSetArg (args[n], XtNright, XtChainLeft); n++; + XtSetArg (args[n], XtNtop, XtChainBottom); n++; + XtSetArg (args[n], XtNbottom, XtChainBottom); n++; + XtSetArg (args[n], XtNfromVert, text); n++; + XtSetArg (args[n], XtNvertDistance, 5); n++; + + prev = NULL; + for (i = 0; i < npairs; i++) { + thisn = n; + XtSetArg (args[thisn], XtNfromHoriz, prev); thisn++; + prev = XtCreateManagedWidget (br[i].name, commandWidgetClass, + form, args, thisn); + br[i].widget = prev; + br[i].print_value = print_value; + XtAddCallback (prev, XtNcallback, handle_button, (XtPointer) &br[i]); + if (default_button && !strcmp(default_button, br[i].name)) { + Dimension border; + + default_exitstatus = br[i].exitstatus; + XtVaGetValues(br[i].widget, XtNborderWidth, &border, NULL); + border *= 2; + XtVaSetValues(br[i].widget, XtNborderWidth, border, NULL); + } + } + return form; +} |