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