xedit.c revision f14f4646
1/* $XConsortium: xedit.c,v 1.28 94/03/26 17:06:28 rws Exp $ */
2
3/*
4 *			  COPYRIGHT 1987
5 *		   DIGITAL EQUIPMENT CORPORATION
6 *		       MAYNARD, MASSACHUSETTS
7 *			ALL RIGHTS RESERVED.
8 *
9 * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
10 * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
11 * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
12 * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
13 *
14 * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
15 * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
16 * SET FORTH ABOVE.
17 *
18 *
19 * Permission to use, copy, modify, and distribute this software and its
20 * documentation for any purpose and without fee is hereby granted, provided
21 * that the above copyright notice appear in all copies and that both that
22 * copyright notice and this permission notice appear in supporting
23 * documentation, and that the name of Digital Equipment Corporation not be
24 * used in advertising or publicity pertaining to distribution of the software
25 * without specific, written prior permission.
26 */
27/* $XFree86: xc/programs/xedit/xedit.c,v 1.17 2002/09/22 07:09:05 paulo Exp $ */
28
29#include "xedit.h"
30#include <X11/Xaw/SmeBSB.h>
31#include <time.h>
32#include <sys/stat.h>
33#include <X11/CoreP.h>
34
35#include <stdlib.h>
36
37#define randomize()	srand((unsigned)time((time_t*)NULL))
38
39static XtActionsRec actions[] = {
40{"quit", QuitAction},
41{"save-file", SaveFile},
42{"load-file", LoadFile},
43#ifdef INCLUDE_XPRINT_SUPPORT
44{"print-file", PrintFile},
45#endif /* INCLUDE_XPRINT_SUPPORT */
46{"find-file", FindFile},
47{"cancel-find-file", CancelFindFile},
48{"file-completion", FileCompletion},
49{"popup-menu", PopupMenu},
50{"kill-file", KillFile},
51{"split-window", SplitWindow},
52{"dir-window", DirWindow},
53{"delete-window", DeleteWindow},
54{"xedit-focus", XeditFocus},
55{"other-window", OtherWindow},
56{"switch-source", SwitchSource},
57#ifndef __UNIXOS2__
58{"lisp-eval", XeditLispEval},
59{"xedit-print-lisp-eval", XeditPrintLispEval},
60{"xedit-keyboard-reset",XeditKeyboardReset},
61#endif
62{"ispell", IspellAction},
63{"line-edit", LineEditAction},
64{"tags", TagsAction}
65};
66
67#define DEF_HINT_INTERVAL	300	/* in seconds, 5 minutes */
68
69static Atom wm_delete_window;
70static Widget hintswindow;
71static int position_format_mask;
72static XawTextPositionInfo infos[3];
73
74Widget topwindow, textwindow, messwidget, labelwindow, filenamewindow;
75Widget scratch, hpane, vpanes[2], labels[3], texts[3], forms[3], positions[3];
76Widget options_popup, dirlabel, dirwindow;
77Boolean international;
78Boolean line_edit;
79XawTextWrapMode wrapmodes[3];
80
81extern void ResetSourceChanged(xedit_flist_item*);
82
83static void makeButtonsAndBoxes(Widget);
84static void HintsTimer(XtPointer, XtIntervalId*);
85static void PositionChanged(Widget, XtPointer, XtPointer);
86static void StartFormatPosition(void);
87static void StartHints(void);
88
89Display *CurDpy;
90
91struct _app_resources app_resources;
92struct _xedit_flist flist;
93
94#define Offset(field) XtOffsetOf(struct _app_resources, field)
95
96static XtResource resources[] = {
97   {"enableBackups", "EnableBackups", XtRBoolean, sizeof(Boolean),
98         Offset(enableBackups), XtRImmediate, FALSE},
99   {"backupNamePrefix", "BackupNamePrefix", XtRString, sizeof(char *),
100         Offset(backupNamePrefix),XtRString, ""},
101   {"backupNameSuffix", "BackupNameSuffix", XtRString, sizeof(char *),
102         Offset(backupNameSuffix),XtRString, ".BAK"},
103   {"hints", "Hint", XtRString, sizeof(char *),
104	 Offset(hints.resource), XtRImmediate, NULL},
105   {"hintsInterval", XtCInterval, XtRInt, sizeof(long),
106	 Offset(hints.interval), XtRImmediate, (XtPointer)DEF_HINT_INTERVAL},
107   {"changedBitmap", XtRBitmap, XtRString, sizeof(char*),
108	 Offset(changed_pixmap_name), XtRString, "dot"},
109   {"positionFormat", "Format", XtRString, sizeof(char*),
110	 Offset(position_format), XtRString, "L%l"},
111   {"autoReplace", "Replace", XtRString, sizeof(char*),
112	 Offset(auto_replace), XtRImmediate, NULL},
113   {"tagsName", "TagsName", XtRString, sizeof(char *),
114         Offset(tagsName), XtRString, "tags"},
115   {"loadTags", "LoadTags", XtRBoolean, sizeof(Boolean),
116	 Offset(loadTags), XtRImmediate, (XtPointer)TRUE},
117};
118
119#undef Offset
120
121#ifdef INCLUDE_XPRINT_SUPPORT
122String fallback_resources[] = {
123    "*international:     True", /* set this globally for ALL widgets to avoid wiered crashes */
124    NULL
125};
126#endif
127
128int
129main(int argc, char *argv[])
130{
131    Boolean		exists;
132    char		*filename;
133    FileAccess		file_access;
134    Widget		source;
135    XtAppContext	appcon;
136    unsigned int	i, num_loaded, lineno;
137
138    num_loaded = lineno = 0;
139
140#ifdef INCLUDE_XPRINT_SUPPORT
141    XtSetLanguageProc(NULL, NULL, NULL);
142#endif
143    topwindow = XtAppInitialize(&appcon, "Xedit", NULL, 0, &argc, argv,
144#ifdef INCLUDE_XPRINT_SUPPORT
145				fallback_resources,
146#else
147				NULL,
148#endif
149				NULL, 0);
150
151    XtAppAddActions(appcon, actions, XtNumber(actions));
152    XtOverrideTranslations(topwindow,
153			   XtParseTranslationTable("<Message>WM_PROTOCOLS: quit()"));
154
155    XtGetApplicationResources(topwindow, (XtPointer) &app_resources, resources,
156			      XtNumber(resources), NULL, 0);
157
158    CurDpy = XtDisplay(topwindow);
159    XawSimpleMenuAddGlobalActions(appcon);
160    XtRegisterGrabAction(PopupMenu, True,
161			 ButtonPressMask | ButtonReleaseMask,
162			 GrabModeAsync, GrabModeAsync);
163
164    makeButtonsAndBoxes(topwindow);
165
166    StartHints();
167    StartFormatPosition();
168    (void)StartHooks(appcon);
169    if (position_format_mask == 0) {
170	for (i = 0; i < 3; i++)
171	    XtRemoveCallback(texts[i], XtNpositionCallback,
172			     PositionChanged, NULL);
173    }
174    XtRealizeWidget(topwindow);
175
176#ifndef __UNIXOS2__
177    XeditLispInitialize();
178#endif
179
180    options_popup = XtCreatePopupShell("optionsMenu", simpleMenuWidgetClass,
181				       topwindow, NULL, 0);
182    XtRealizeWidget(options_popup);
183    XtAddCallback(XtCreateManagedWidget("ispell", smeBSBObjectClass,
184					options_popup, NULL, 0),
185		  XtNcallback, IspellCallback, NULL);
186    CreateEditPopup();
187
188    wm_delete_window = XInternAtom(XtDisplay(topwindow), "WM_DELETE_WINDOW",
189				   False);
190    (void)XSetWMProtocols(XtDisplay(topwindow), XtWindow(topwindow),
191			  &wm_delete_window, 1);
192
193    /* This first call is just to save the default font and colors */
194    UpdateTextProperties(0);
195
196    if (argc > 1) {
197	xedit_flist_item	*item;
198	Arg			args[2];
199	unsigned int		num_args;
200
201	for (i = 1; i < argc; i++) {
202	    struct stat st;
203
204	    if (argv[i][0] == '+') {
205		char	*endptr;
206
207		lineno = strtol(argv[i], &endptr, 10);
208		/* Don't warn or anything about incorrect input? */
209		if (*endptr)
210		    lineno = 0;
211		continue;
212	    }
213
214	    filename = ResolveName(argv[i]);
215	    if (filename == NULL || FindTextSource(NULL, filename) != NULL)
216		continue;
217
218	    num_args = 0;
219	    if (stat(filename, &st) == 0 && !S_ISREG(st.st_mode)) {
220		if (S_ISDIR(st.st_mode)) {
221		    if (!num_loaded) {
222			char path[BUFSIZ + 1];
223
224			strncpy(path, filename, sizeof(path) - 2);
225			path[sizeof(path) - 2] = '\0';
226			if (*path) {
227			    if (path[strlen(path) - 1] != '/')
228				strcat(path, "/");
229			}
230			else
231			    strcpy(path, "./");
232			XtSetArg(args[0], XtNlabel, "");
233			XtSetValues(dirlabel, args, 1);
234			SwitchDirWindow(True);
235			DirWindowCB(dirwindow, path, NULL);
236			++num_loaded;
237		    }
238		    continue;
239		}
240	    }
241
242	    switch (file_access = CheckFilePermissions(filename, &exists)) {
243	    case NO_READ:
244		if (exists)
245		    XeditPrintf("File %s exists, and could not be opened for "
246				"reading.\n", argv[i]);
247		else
248		    XeditPrintf("File %s does not exist, and the directory "
249				"could not be opened for writing.\n", argv[i]);
250		break;
251	    case READ_OK:
252		XtSetArg(args[num_args], XtNeditType, XawtextRead); num_args++;
253		XeditPrintf("File %s opened READ ONLY.\n", argv[i]);
254		break;
255	    case WRITE_OK:
256		XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++;
257		XeditPrintf("File %s opened read - write.\n", argv[i]);
258		break;
259	    }
260	    if (file_access != NO_READ) {
261		int flags;
262
263		if (exists) {
264		    flags = EXISTS_BIT;
265		    XtSetArg(args[num_args], XtNstring, filename);num_args++;
266		}
267		else {
268		    flags = 0;
269		    XtSetArg(args[num_args], XtNstring, NULL);	  num_args++;
270		}
271		source = XtVaCreateWidget("textSource", international ?
272					  multiSrcObjectClass
273					  : asciiSrcObjectClass, topwindow,
274					  XtNtype, XawAsciiFile,
275					  XtNeditType, XawtextEdit,
276					  NULL, NULL);
277		XtSetValues(source, args, num_args);
278		item = AddTextSource(source, argv[i], filename,
279				     flags, file_access);
280		XtAddCallback(item->source, XtNcallback, SourceChanged,
281			      (XtPointer)item);
282		if (exists && file_access == WRITE_OK) {
283		    item->mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
284		    item->mtime = st.st_mtime;
285		}
286		if (!num_loaded)
287		    SwitchTextSource(item);
288		++num_loaded;
289		ResetSourceChanged(item);
290	    }
291	}
292    }
293
294    if (!flist.pixmap && strlen(app_resources.changed_pixmap_name)) {
295	XrmValue from, to;
296
297	from.size = strlen(app_resources.changed_pixmap_name);
298	from.addr = app_resources.changed_pixmap_name;
299	to.size = sizeof(Pixmap);
300	to.addr = (XtPointer)&(flist.pixmap);
301
302	XtConvertAndStore(flist.popup, XtRString, &from, XtRBitmap, &to);
303    }
304
305    if (num_loaded == 0) {
306	XtSetKeyboardFocus(topwindow, filenamewindow);
307	XtVaSetValues(textwindow, XtNwrap, XawtextWrapLine, NULL);
308    }
309    else {
310	XtSetKeyboardFocus(topwindow, textwindow);
311	if (lineno) {
312	    XawTextPosition position;
313
314	    source = XawTextGetSource(textwindow);
315	    position = RSCAN(XawTextGetInsertionPoint(textwindow),
316			     lineno, False);
317	    position = LSCAN(position, 1, False);
318	    XawTextSetInsertionPoint(textwindow, position);
319	}
320    }
321
322    XtAppMainLoop(appcon);
323    return EXIT_SUCCESS;
324}
325
326static void
327makeButtonsAndBoxes(Widget parent)
328{
329    Widget outer, b_row, viewport;
330    Arg arglist[10];
331    Cardinal num_args;
332    xedit_flist_item *item;
333    static char *labelWindow = "labelWindow", *editWindow = "editWindow";
334    static char *formWindow = "formWindow", *positionWindow = "positionWindow";
335
336    outer = XtCreateManagedWidget("paned", panedWidgetClass, parent,
337				  NULL, ZERO);
338
339    b_row = XtCreateManagedWidget("buttons", panedWidgetClass, outer, NULL, ZERO);
340    {
341	MakeCommandButton(b_row, "quit", DoQuit);
342	MakeCommandButton(b_row, "save", DoSave);
343	MakeCommandButton(b_row, "load", DoLoad);
344#ifdef INCLUDE_XPRINT_SUPPORT
345	MakeCommandButton(b_row, "print", DoPrint);
346#endif /* INCLUDE_XPRINT_SUPPORT */
347	filenamewindow = MakeStringBox(b_row, "filename", NULL);
348    }
349    hintswindow = XtCreateManagedWidget("bc_label", labelWidgetClass,
350					outer, NULL, ZERO);
351
352    num_args = 0;
353    XtSetArg(arglist[num_args], XtNeditType, XawtextEdit);		++num_args;
354    messwidget = XtCreateManagedWidget("messageWindow", asciiTextWidgetClass,
355				       outer, arglist, num_args);
356
357    num_args = 0;
358    XtSetArg(arglist[num_args], XtNorientation, XtorientHorizontal);	++num_args;
359    hpane = XtCreateManagedWidget("hpane", panedWidgetClass, outer,
360				  arglist, num_args);
361
362    num_args = 0;
363    XtSetArg(arglist[num_args], XtNorientation, XtorientVertical);	++num_args;
364    vpanes[0] = XtCreateManagedWidget("vpane", panedWidgetClass, hpane,
365				      arglist, num_args);
366    XtSetArg(arglist[num_args], XtNheight, 1);				++num_args;
367    XtSetArg(arglist[num_args], XtNwidth, 1);				++num_args;
368    vpanes[1] = XtCreateWidget("vpane", panedWidgetClass, hpane,
369			       arglist, num_args);
370
371    forms[0] = XtCreateManagedWidget(formWindow, formWidgetClass,
372				     vpanes[0], NULL, 0);
373    labelwindow = XtCreateManagedWidget(labelWindow,labelWidgetClass,
374					forms[0], NULL, 0);
375    labels[0] = labelwindow;
376    positions[0] = XtCreateManagedWidget(positionWindow,labelWidgetClass,
377					 forms[0], NULL, 0);
378
379    forms[2] = XtCreateWidget(formWindow, formWidgetClass,
380			      vpanes[1], NULL, 0);
381    labels[2] = XtCreateManagedWidget(labelWindow,labelWidgetClass,
382				      forms[2], NULL, 0);
383    positions[2] = XtCreateManagedWidget(positionWindow,labelWidgetClass,
384					 forms[2], NULL, 0);
385
386    num_args = 0;
387    XtSetArg(arglist[num_args], XtNtype, XawAsciiFile);			++num_args;
388    XtSetArg(arglist[num_args], XtNeditType, XawtextEdit);		++num_args;
389    textwindow =  XtCreateManagedWidget(editWindow, asciiTextWidgetClass,
390					vpanes[0], arglist, num_args);
391
392#ifdef INCLUDE_XPRINT_SUPPORT
393    international = True;
394#else
395    /* Get international resource value form the textwindow */
396    num_args = 0;
397    XtSetArg(arglist[num_args], XtNinternational, &international);	++num_args;
398    XtGetValues(textwindow, arglist, num_args);
399#endif
400
401    num_args = 0;
402    XtSetArg(arglist[num_args], XtNtype, XawAsciiFile);			++num_args;
403    XtSetArg(arglist[num_args], XtNeditType, XawtextEdit);		++num_args;
404    scratch = XtVaCreateWidget("textSource", international ?
405			       multiSrcObjectClass :
406			       asciiSrcObjectClass, topwindow,
407			       XtNtype, XawAsciiFile,
408			       XtNeditType, XawtextEdit,
409			       NULL, NULL);
410    XtSetValues(scratch, arglist, num_args);
411
412    num_args = 0;
413    XtSetArg(arglist[num_args], XtNtextSource, scratch);		++num_args;
414    XtSetValues(textwindow, arglist, num_args);
415
416    texts[0] = textwindow;
417    num_args = 0;
418    XtSetArg(arglist[num_args], XtNtextSource, scratch);		++num_args;
419    XtSetArg(arglist[num_args], XtNdisplayCaret, False);		++num_args;
420    texts[2] = XtCreateWidget(editWindow, asciiTextWidgetClass,
421			      vpanes[1], arglist, num_args);
422
423    forms[1] = XtCreateWidget(formWindow, formWidgetClass,
424			      vpanes[0], NULL, 0);
425    labels[1] = XtCreateManagedWidget(labelWindow,labelWidgetClass,
426				      forms[1], NULL, 0);
427    positions[1] = XtCreateManagedWidget(positionWindow,labelWidgetClass,
428					 forms[1], NULL, 0);
429
430    texts[1] = XtCreateWidget(editWindow, asciiTextWidgetClass,
431			      vpanes[0], arglist, num_args);
432
433    dirlabel = XtCreateWidget("dirlabel", labelWidgetClass,
434			      vpanes[1], NULL, 0);
435    num_args = 0;
436    XtSetArg(arglist[num_args], XtNheight, 1);				++num_args;
437    XtSetArg(arglist[num_args], XtNwidth, 1);				++num_args;
438    viewport = XtCreateWidget("viewport", viewportWidgetClass,
439			      vpanes[1], arglist, num_args);
440    dirwindow = XtCreateManagedWidget("dirwindow", listWidgetClass,
441				      viewport, NULL, 0);
442
443    item = AddTextSource(scratch, "*scratch*", "*scratch*",
444			 0, WRITE_OK);
445    item->wrap = XawtextWrapLine;
446    item->flags |= WRAP_BIT;
447    XtAddCallback(item->source, XtNcallback, SourceChanged,
448		  (XtPointer)item);
449    ResetSourceChanged(item);
450    flist.current = item;
451
452    for (num_args = 0; num_args < 3; num_args++)
453	XtAddCallback(texts[num_args], XtNpositionCallback, PositionChanged, NULL);
454
455    for (num_args = 0; num_args < 3; num_args++) {
456	XtSetArg(arglist[0], XtNwrap, &wrapmodes[num_args]);
457	XtGetValues(texts[num_args], arglist, 1);
458    }
459
460    XtAddCallback(dirwindow, XtNcallback, DirWindowCB, NULL);
461}
462
463/*	Function Name: Feep
464 *	Description: feeps the bell.
465 *	Arguments: none.
466 *	Returns: none.
467 */
468
469void
470Feep(void)
471{
472  XBell(CurDpy, 0);
473}
474
475#define	l_BIT		0x01
476#define	c_BIT		0x02
477#define	p_BIT		0x04
478#define	s_BIT		0x08
479#define MAX_FMT_LEN	30
480
481static void
482StartFormatPosition(void)
483{
484    char *fmt = app_resources.position_format;
485
486    if (fmt)
487	while (*fmt)
488	    if (*fmt++ == '%') {
489		int len = 0;
490
491		if (*fmt == '-') {
492		    ++fmt;
493		    ++len;
494		}
495		while (*fmt >= '0' && *fmt <= '9') {
496		    ++fmt;
497		    if (++len >= MAX_FMT_LEN) {
498			XtAppWarning(XtWidgetToApplicationContext(topwindow),
499				     "Format too large to formatPosition");
500			position_format_mask = 0;
501			return;
502		    }
503		}
504		switch (*fmt++) {
505		    case 'l':	position_format_mask |= l_BIT;	break;
506		    case 'c':	position_format_mask |= c_BIT;	break;
507		    case 'p':	position_format_mask |= p_BIT;	break;
508		    case 's':	position_format_mask |= s_BIT;	break;
509		    case '%':	break;
510		    default: {
511			char msg[256];
512
513			XmuSnprintf(msg, sizeof(msg),
514				    "Unknown format \"%%%c\" in positionFormat",
515				    fmt[-1]);
516			XtAppWarning(XtWidgetToApplicationContext(topwindow),
517				     msg);
518			position_format_mask = 0;
519			return;
520		    }
521		}
522	    }
523}
524
525/*ARGSUSED*/
526static void
527PositionChanged(Widget w, XtPointer client_data, XtPointer call_data)
528{
529    int idx;
530    XawTextPositionInfo *info = (XawTextPositionInfo*)call_data;
531
532    for (idx = 0; idx < 3; idx++)
533	if (w == texts[idx])
534	    break;
535    if (idx > 2)
536	return;
537
538    if (((position_format_mask & l_BIT)
539	  && infos[idx].line_number != info->line_number)
540	|| ((position_format_mask & c_BIT)
541	    && infos[idx].column_number != info->column_number)
542	|| ((position_format_mask & p_BIT)
543	    && infos[idx].insert_position != info->insert_position)
544	|| ((position_format_mask & s_BIT)
545	    && infos[idx].last_position != info->last_position)
546	|| infos[idx].overwrite_mode != info->overwrite_mode) {
547	int len = 6;
548	Arg args[1];
549	char buffer[256], *str = app_resources.position_format;
550	char fmt_buf[MAX_FMT_LEN + 2], *fmt;
551
552	memcpy(&infos[idx], info, sizeof(XawTextPositionInfo));
553	if (info->overwrite_mode)
554	    strcpy(buffer, "Ovrwt ");
555	else
556	    strcpy(buffer, "      ");
557	while (*str) {
558	    switch (*str) {
559		case '%':
560		    fmt = fmt_buf;
561		    *fmt++ = *str++;
562		    if (*str == '-')
563			*fmt++ = *str++;
564		    /*CONSTCOND*/
565		    while (*str >= '0' && *str <= '9') {
566			/* StartPositionFormat() already checked the format
567			 * length.
568			 */
569			*fmt++ = *str++;
570		    }
571		    *fmt++ = 'd';
572		    *fmt = '\0';
573		    switch (*str) {
574			case 'l':
575			    XmuSnprintf(&buffer[len], sizeof(buffer) - len,
576					fmt_buf, info->line_number);
577			    break;
578			case 'c':
579			    XmuSnprintf(&buffer[len], sizeof(buffer) - len,
580					fmt_buf, info->column_number);
581			    break;
582			case 'p':
583			    XmuSnprintf(&buffer[len], sizeof(buffer) - len,
584					fmt_buf, info->insert_position);
585			    break;
586			case 's':
587			    XmuSnprintf(&buffer[len], sizeof(buffer) - len,
588					fmt_buf, info->last_position);
589			    break;
590			case '%':
591			    strcpy(&buffer[len], "%");
592			    break;
593		    }
594		    len += strlen(&buffer[len]);
595		    break;
596		default:
597		    buffer[len++] = *str;
598		    break;
599	    }
600	    if (len >= sizeof(buffer) - 1)
601		break;
602	    ++str;
603	}
604	buffer[len] = '\0';
605
606	XtSetArg(args[0], XtNlabel, buffer);
607	XtSetValues(positions[idx], args, 1);
608    }
609}
610
611/*ARGSUSED*/
612static void
613HintsTimer(XtPointer closure, XtIntervalId *id)
614{
615    Arg args[1];
616    xedit_hints *hints = (xedit_hints*)closure;
617
618    hints->cur_hint = rand() % hints->num_hints;
619
620    XtSetArg(args[0], XtNlabel, hints->hints[hints->cur_hint]);
621    XtSetValues(hintswindow, args, 1);
622
623    hints->timer = XtAppAddTimeOut(XtWidgetToApplicationContext(topwindow),
624				   hints->interval, HintsTimer, closure);
625}
626
627#define MAX_HINT_LEN		255
628#define MIN_HINT_INTERVAL	5
629static void
630StartHints(void)
631{
632    char *str, *p;
633    unsigned i, len;
634    xedit_hints *hints = &(app_resources.hints);
635
636    /* if resource was not set, or was overriden */
637    if (hints->resource == NULL || !*hints->resource)
638	return;
639
640    randomize();
641
642    if (hints->interval < MIN_HINT_INTERVAL)
643	hints->interval = DEF_HINT_INTERVAL;
644    hints->interval *= 1000;
645    hints->hints = (char**)XtMalloc(sizeof(char*));
646    hints->hints[hints->cur_hint = 0] = p = hints->resource;
647    hints->num_hints = 1;
648
649    while ((p = strchr(p, '\n')) != NULL) {
650	if (*++p == '\0')
651	    break;
652	hints->hints = (char**)
653	    XtRealloc((char*)hints->hints,
654		      sizeof(char*) * (hints->num_hints + 1));
655	hints->hints[hints->num_hints++] = p;
656    }
657
658    /* make a private copy of the resource values, so that one can change
659     * the Xrm database safely.
660     */
661    for (i = 0; i < hints->num_hints; i++) {
662	if ((p = strchr(hints->hints[i], '\n')) != NULL)
663	    len = p - hints->hints[i];
664	else
665	    len = strlen(hints->hints[i]);
666	if (len > MAX_HINT_LEN)
667	    len = MAX_HINT_LEN;
668	str = XtMalloc(len + 1);
669	strncpy(str, hints->hints[i], len);
670	str[len] = '\0';
671	hints->hints[i] = str;
672    }
673
674    hints->timer = XtAppAddTimeOut(XtWidgetToApplicationContext(topwindow),
675				   hints->interval, HintsTimer,
676				   (XtPointer)hints);
677}
678