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 43static 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 68static Atom wm_delete_window; 69static Widget hintswindow; 70static int position_format_mask; 71static XawTextPositionInfo infos[3]; 72 73Widget topwindow, textwindow, messwidget, labelwindow, filenamewindow; 74Widget scratch, hpane, vpanes[2], labels[3], texts[3], forms[3], positions[3]; 75Widget options_popup, dirlabel, dirwindow; 76Boolean international; 77Boolean line_edit; 78XawTextWrapMode wrapmodes[3]; 79 80extern void ResetSourceChanged(xedit_flist_item*); 81 82static void makeButtonsAndBoxes(Widget); 83static void HintsTimer(XtPointer, XtIntervalId*); 84static void PositionChanged(Widget, XtPointer, XtPointer); 85static void StartFormatPosition(void); 86static void StartHints(void); 87 88Display *CurDpy; 89 90struct _app_resources app_resources; 91struct _xedit_flist flist; 92 93#define Offset(field) XtOffsetOf(struct _app_resources, field) 94 95static 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 120int 121main(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 332static void 333makeButtonsAndBoxes(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 468void 469Feep(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 480static void 481StartFormatPosition(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*/ 525static void 526PositionChanged(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*/ 611static void 612HintsTimer(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 628static void 629StartHints(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