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