home *** CD-ROM | disk | FTP | other *** search
- /*
- * xmessage - utility for querying users
- *
- * Copyright 1988,1991 Massachusetts Institute of Technology
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of M.I.T. not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission. M.I.T. makes no representations about the
- * suitability of this software for any purpose. It is provided "as is"
- * without express or implied warranty.
- */
-
- #include <X11/Intrinsic.h>
- #include <X11/StringDefs.h>
- #include <stdio.h>
- #include <string.h>
- #include <sys/types.h>
-
- #include <X11/Xaw/AsciiText.h>
- #include <X11/Xaw/Command.h>
- #include <X11/Xaw/Form.h>
-
- #define SCROLLBAR_WIDTH 14
- #define SCROLLBAR_HEIGHT 14
-
- extern char *malloc();
- extern char *ProgramName;
- extern Widget default_button_widget;
- extern char *copy_stdin();
-
- typedef struct _ButtonRecord {
- char *name; /* button name */
- char *filename; /* file to unlink on exit, or NULL */
- int exitstatus; /* exit status for this button */
- Boolean print_value; /* print button name on exit? */
- Widget widget; /* button Command widget */
- } ButtonRecord;
-
-
- /*
- * event handler to warp the pointer to the default button when the button
- * is exposed.
- */
-
- static XtEventHandler warp_to_button (w, closure, event, continue_to_dispatch)
- Widget w; /* widget that was exposed */
- XtPointer closure; /* ButtonRecord to warp pointer to */
- XEvent *event; /* event */
- Boolean *continue_to_dispatch; /* ignored */
- {
- ButtonRecord *br;
- Arg args[3]; /* argument list */
- Cardinal num_args;
- Dimension width, height, b_width;
- int x, y;
-
- br = (ButtonRecord *) closure;
-
- num_args = 0;
- (void) XtSetArg(args[num_args], XtNwidth, &width); num_args++;
- (void) XtSetArg(args[num_args], XtNheight, &height); num_args++;
- (void) XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
- (void) XtGetValues(br->widget, args, num_args);
-
- width += 2 * b_width;
- height += 2 * b_width;
- x = width / 2;
- y = height / 2;
-
- XWarpPointer (XtDisplay(br->widget), None, XtWindow(br->widget),
- 0, 0, 0, 0, x, y);
-
- XtRemoveEventHandler(w, ExposureMask, False, (XtEventHandler)warp_to_button,
- (XtPointer) br);
- }
-
-
- /*
- * compute width and height of message in terms of columns and lines
- */
- static void get_message_dimensions (message, width, height)
- char *message; /* message string to be displayed */
- int *width; /* width needed to display string */
- int *height; /* height needed to display string */
- {
- int lines, cols, maxcols;
- char *cp;
-
- *width = 0;
- *height = 0;
-
- lines = 0;
- cols = 0;
- maxcols = 0;
-
- for (cp = message; *cp; cp++) {
- switch (*cp)
- {
- case '\n':
- lines++;
- if (cols > maxcols) maxcols = cols;
- cols = 0;
- break;
-
- case '\t':
- cols = ((cols >> 3) + 1) << 3;
-
- default:
- cols++;
- break;
- }
- }
-
- if (cols > 0) {
- lines++;
- if (cols > maxcols) maxcols = cols;
- }
-
- *width = maxcols;
- *height = lines;
- }
-
-
- /*
- * compute width and height of file contents in terms of columns and lines
- */
- static void get_file_dimensions (filename, width, height)
- char *filename; /* file to be displayed */
- int *width; /* width needed to display string */
- int *height; /* height needed to display string */
- {
- int lines, cols, maxcols;
- int c;
- FILE *fp;
-
- *width = 0;
- *height = 0;
-
- fp = fopen (filename, "r");
- if (!fp) return;
-
- lines = 0;
- cols = 0;
- maxcols = 0;
-
- while ((c = getc(fp)) != EOF) {
- switch (c)
- {
- case '\n':
- lines++;
- if (cols > maxcols)
- maxcols = cols;
- cols = 0;
- break;
-
- case '\t':
- cols = ((cols >> 3) + 1) << 3;
-
- default:
- cols++;
- break;
- }
- }
-
- if (cols > 0) {
- lines++;
- if (cols > maxcols) maxcols = cols;
- }
-
- (void) fclose (fp);
- *width = maxcols;
- *height = lines;
- }
-
-
- /*
- * strip quotes from button names
- */
- 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:1,no:2, ..."
- * 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;
- }
-
- /*
- * callback to handle button being pressed
- */
-
- /* ARGSUSED */
- static void handle_button (w, closure, client_data)
- Widget w;
- XtPointer closure;
- XtPointer client_data;
- {
- ButtonRecord *br = (ButtonRecord *) closure;
-
- if (br->print_value) printf("%s\n", br->name);
- if (br->filename) (void) unlink(br->filename);
- exit (br->exitstatus);
- }
-
- Widget make_queryform(parent, msgstr, filename, button_list,
- print_value, default_button, warp_button,
- columns, min_columns, max_columns,
- lines, min_lines, max_lines)
- Widget parent; /* into whom widget should be placed */
- char *msgstr; /* message string or NULL */
- char *filename; /* file name or NULL */
- char *button_list; /* list of button title:status */
- Boolean print_value; /* print button string on stdout? */
- char *default_button; /* button activated by Return */
- char *warp_button; /* button to warp cursor to */
- int columns; /* requested size of message box */
- int min_columns; /* min size of message box */
- int max_columns; /* max size of message box */
- int lines; /* requested size of message box */
- int min_lines; /* min size of message box */
- int max_lines; /* max size of message box */
- {
- ButtonRecord *br;
- int npairs, i;
- Widget form, text, prev;
- Arg args[20];
- Cardinal n, thisn;
- int width, height;
- int msg_lines, msg_columns;
- int font_width, font_height;
- Dimension old_width, old_height;
- char *unlink_filename;
- XFontStruct *font;
- Dimension borderWidth;
- Position topMargin, bottomMargin, leftMargin, rightMargin;
- Widget warp_button_widget = NULL;
- int default_button_index = -1;
- int warp_button_index = -1;
-
- npairs = parse_name_and_exit_code_list (button_list, &br);
-
- form = XtCreateManagedWidget ("form", formWidgetClass, parent, NULL, 0);
-
- n = 0;
- XtSetArg (args[n], XtNleft, XtChainLeft); n++;
- XtSetArg (args[n], XtNright, XtChainRight); n++;
- XtSetArg (args[n], XtNtop, XtChainTop); n++;
- XtSetArg (args[n], XtNbottom, XtChainBottom); n++;
- XtSetArg (args[n], XtNresizable, TRUE); n++;
-
- if (filename) {
- if (*filename == '-') unlink_filename = filename = copy_stdin ();
- (void) get_file_dimensions(filename, &msg_columns, &msg_lines);
- XtSetArg (args[n], XtNstring, filename); n++;
- XtSetArg (args[n], XtNtype, XawAsciiFile); n++;
- }
- else {
- if (!msgstr) msgstr = "xmessage called with no message string";
- (void) get_message_dimensions(msgstr, &msg_columns, &msg_lines);
- XtSetArg (args[n], XtNstring, msgstr); n++;
- XtSetArg (args[n], XtNtype, XawAsciiString); n++;
- }
- XtSetArg (args[n], XtNscrollHorizontal, XawtextScrollWhenNeeded); n++;
- XtSetArg (args[n], XtNscrollVertical, XawtextScrollWhenNeeded); n++;
-
- text = XtCreateManagedWidget ("text", asciiTextWidgetClass, form, args, n);
-
- /*
- * Interrogate the text widget to find out which font it is using,
- * so we can determine the dimensions of its character cell in order
- * to resize the text widget.
- *
- * Note that if the user has explicitly specified a geometry then
- * this resizing is for naught.
- */
-
- n = 0;
- XtSetArg (args[n], XtNborderWidth, &borderWidth); n++;
- XtSetArg (args[n], XtNtopMargin, &topMargin); n++;
- XtSetArg (args[n], XtNbottomMargin, &bottomMargin); n++;
- XtSetArg (args[n], XtNleftMargin, &leftMargin); n++;
- XtSetArg (args[n], XtNrightMargin, &rightMargin); n++;
- XtSetArg (args[n], XtNwidth, &old_width); n++;
- XtSetArg (args[n], XtNheight, &old_height); n++;
- XtSetArg (args[n], XtNfont, &font); n++;
-
- XtGetValues(text, args, n);
-
- font_width = font->max_bounds.width;
- font_height = font->ascent + font->descent;
-
- width = 0;
- height = 0;
-
- if (columns == 0) { /* no explicit columns on command line */
- columns = msg_columns; /* use actual columns in the message */
- if (columns < min_columns) columns = min_columns;
- if (columns > max_columns) {
- columns = max_columns;
- height += SCROLLBAR_HEIGHT;
- }
- }
- width += columns * font_width;
- width += borderWidth + leftMargin + rightMargin + borderWidth;
-
- if (lines == 0) { /* no explicit lines on command line */
- lines = msg_lines; /* use actual lines in the message */
- if (lines < min_lines) lines = min_lines;
- if (lines > max_lines) {
- lines = max_lines;
- width += SCROLLBAR_WIDTH;
- }
- }
- height += lines * font_height;
- height += borderWidth + topMargin + bottomMargin + borderWidth;
-
- if (width < old_width) width = old_width;
- if (height < old_height) height = old_height;
-
- n = 0;
- XtSetArg (args[n], XtNwidth, (Dimension) width); n++;
- XtSetArg (args[n], XtNheight, (Dimension) height); n++;
-
- XtSetValues(text, args, n);
-
- /*
- * 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;
- br[i].filename = unlink_filename;
- XtAddCallback (prev, XtNcallback, handle_button, (XtPointer) &br[i]);
-
- if (default_button && !strcmp(default_button, br[i].name))
- default_button_index = i;
-
- if (warp_button && !strcmp(warp_button, br[i].name))
- warp_button_index = i;
- }
-
- /*
- * if we didn't find a warp button, possibly the default button
- * is also the warp button
- */
- if (warp_button_index < 0 && default_button_index >= 0 &&
- warp_button != NULL && !strcmp(warp_button,"default")) {
- warp_button_index = default_button_index;
- }
-
- /*
- * if there is a default button, double its border width, then adjust
- * the vertical distance of all other buttons to maintain alignment
- * with the default button
- */
- if (default_button_index >= 0) {
- Dimension old_border, new_border;
- default_button_widget = br[default_button_index].widget;
- XtVaGetValues(default_button_widget, XtNborderWidth, &old_border, NULL);
- new_border = old_border * 2;
- XtVaSetValues(default_button_widget, XtNborderWidth, new_border, NULL);
-
- for (i = 0; i < npairs; i++) {
- if (i != default_button_index) {
- int vertdistance;
- XtVaGetValues(br[i].widget, XtNvertDistance, &vertdistance, NULL);
- vertdistance += old_border;
- XtVaSetValues(br[i].widget, XtNvertDistance, vertdistance, NULL);
- }
- }
- }
- else if (default_button != NULL && *default_button != '\0') {
- fprintf(stderr, "%s: no such default button '%s'\n",
- ProgramName, default_button);
- }
-
- /*
- * if there is a warp button, set up an exposure handler to do the warp
- */
- if (warp_button_index >= 0) {
- warp_button_widget = br[warp_button_index].widget;
- XtAddEventHandler(warp_button_widget, ExposureMask, False,
- (XtEventHandler)warp_to_button, (XtPointer) &br[warp_button_index]);
- }
- else if (warp_button != NULL && *warp_button != '\0') {
- fprintf(stderr, "%s: no such warp button '%s'\n",
- ProgramName, warp_button);
- }
-
- return form;
- }
-