1 /*******************************************************************************
2 *									       *
3 * preferences.c -- Nirvana Editor preferences processing		       *
4 *									       *
5 * Copyright (C) 1999 Mark Edel						       *
6 *									       *
7 * This is free software; you can redistribute it and/or modify it under the    *
8 * terms of the GNU General Public License as published by the Free Software    *
9 * Foundation; either version 2 of the License, or (at your option) any later   *
10 * version. In addition, you may distribute version of this program linked to   *
11 * Motif or Open Motif. See README for details.                                 *
12 * 									       *
13 * This software is distributed in the hope that it will be useful, but WITHOUT *
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or        *
15 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License *
16 * for more details.							       *
17 * 									       *
18 * You should have received a copy of the GNU General Public License along with *
19 * software; if not, write to the Free Software Foundation, Inc., 59 Temple     *
20 * Place, Suite 330, Boston, MA  02111-1307 USA		                       *
21 *									       *
22 * Nirvana Text Editor	    						       *
23 * April 20, 1993							       *
24 *									       *
25 * Written by Mark Edel							       *
26 *									       *
27 *******************************************************************************/
28 
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
32 
33 #include "preferences.h"
34 #include "textBuf.h"
35 #include "nedit.h"
36 #include "menu.h"
37 #include "text.h"
38 #include "search.h"
39 #include "window.h"
40 #include "userCmds.h"
41 #include "highlight.h"
42 #include "highlightData.h"
43 #include "help.h"
44 #include "regularExp.h"
45 #include "smartIndent.h"
46 #include "windowTitle.h"
47 #include "server.h"
48 #include "tags.h"
49 #include "../util/prefFile.h"
50 #include "../util/misc.h"
51 #include "../util/DialogF.h"
52 #include "../util/managedList.h"
53 #include "../util/fontsel.h"
54 #include "../util/fileUtils.h"
55 #include "../util/utils.h"
56 #include "../util/nedit_malloc.h"
57 
58 #include <ctype.h>
59 #include <pwd.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <stdio.h>
63 #include <unistd.h>
64 #include <sys/stat.h>
65 #ifdef VMS
66 #include "../util/VMSparam.h"
67 #else
68 #ifndef __MVS__
69 #include <sys/param.h>
70 #endif
71 #include "../util/clearcase.h"
72 #endif /*VMS*/
73 
74 #include <Xm/Xm.h>
75 #include <Xm/SelectioB.h>
76 #include <Xm/Form.h>
77 #include <Xm/List.h>
78 #include <Xm/SeparatoG.h>
79 #include <Xm/LabelG.h>
80 #include <Xm/Label.h>
81 #include <Xm/PushBG.h>
82 #include <Xm/PushB.h>
83 #include <Xm/ToggleBG.h>
84 #include <Xm/ToggleB.h>
85 #include <Xm/RowColumn.h>
86 #include <Xm/CascadeBG.h>
87 #include <Xm/Frame.h>
88 #include <Xm/Text.h>
89 
90 #ifdef HAVE_DEBUG_H
91 #include "../debug.h"
92 #endif
93 
94 #if XmVersion >= 1002
95 #define MENU_WIDGET(w) (XmGetPostedFromWidget(XtParent(w)))
96 #else
97 #define MENU_WIDGET(w) (w)
98 #endif
99 
100 #define PREF_FILE_VERSION "5.6"
101 
102 /* New styles added in 5.2 for auto-upgrade */
103 #define ADD_5_2_STYLES " Pointer:#660000:Bold\nRegex:#009944:Bold\nWarning:brown2:Italic"
104 
105 /* maximum number of word delimiters allowed (256 allows whole character set) */
106 #define MAX_WORD_DELIMITERS 256
107 
108 /* maximum number of file extensions allowed in a language mode */
109 #define MAX_FILE_EXTENSIONS 20
110 
111 /* Return values for checkFontStatus */
112 enum fontStatus {GOOD_FONT, BAD_PRIMARY, BAD_FONT, BAD_SIZE, BAD_SPACING};
113 
114 /* enumerated type preference strings
115 ** The order of the elements in this array must be exactly the same
116 ** as the order of the corresponding integers of the enum SearchType
117 ** defined in search.h (!!)
118 */
119 static char *SearchMethodStrings[] = {
120   	"Literal", "CaseSense", "RegExp",
121 	"LiteralWord", "CaseSenseWord", "RegExpNoCase",
122 	NULL
123 };
124 
125 #ifdef REPLACE_SCOPE
126 /* enumerated default scope for replace dialog if a selection exists when
127 ** the dialog is popped up.
128 */
129 static char *ReplaceDefScopeStrings[] = {
130 	"Window", "Selection", "Smart", NULL
131 };
132 #endif
133 
134 #define N_WRAP_STYLES 3
135 static char *AutoWrapTypes[N_WRAP_STYLES+3] = {"None", "Newline", "Continuous",
136     	"True", "False", NULL};
137 #define N_INDENT_STYLES 3
138 static char *AutoIndentTypes[N_INDENT_STYLES+3] = {"None", "Auto",
139     	"Smart", "True", "False", NULL};
140 #define N_VIRTKEY_OVERRIDE_MODES 3
141 static char *VirtKeyOverrideModes[N_VIRTKEY_OVERRIDE_MODES+1] = { "Never",
142 	"Auto", "Always", NULL};
143 
144 #define N_SHOW_MATCHING_STYLES 3
145 /* For backward compatibility, "False" and "True" are still accepted.
146    They are internally converted to "Off" and "Delimiter" respectively.
147    NOTE: N_SHOW_MATCHING_STYLES must correspond to the number of
148          _real_ matching styles, not counting False & True.
149          False and True should also be the last ones in the list. */
150 static char *ShowMatchingTypes[] = {"Off", "Delimiter", "Range",
151 	"False", "True", NULL};
152 
153 /*  This array must be kept in parallel to the enum truncSubstitution
154     in nedit.h  */
155 static char* TruncSubstitutionModes[] = {"Silent", "Fail", "Warn", "Ignore", NULL};
156 
157 /* suplement wrap and indent styles w/ a value meaning "use default" for
158    the override fields in the language modes dialog */
159 #define DEFAULT_WRAP -1
160 #define DEFAULT_INDENT -1
161 #define DEFAULT_TAB_DIST -1
162 #define DEFAULT_EM_TAB_DIST -1
163 
164 /* list of available language modes and language specific preferences */
165 static int NLanguageModes = 0;
166 typedef struct {
167     char *name;
168     int nExtensions;
169     char **extensions;
170     char *recognitionExpr;
171     char *defTipsFile;
172     char *delimiters;
173     int wrapStyle;
174     int indentStyle;
175     int tabDist;
176     int emTabDist;
177 } languageModeRec;
178 static languageModeRec *LanguageModes[MAX_LANGUAGE_MODES];
179 
180 /* Language mode dialog information */
181 static struct {
182     Widget shell;
183     Widget nameW;
184     Widget extW;
185     Widget recogW;
186     Widget defTipsW;
187     Widget delimitW;
188     Widget managedListW;
189     Widget tabW;
190     Widget emTabW;
191     Widget defaultIndentW;
192     Widget noIndentW;
193     Widget autoIndentW;
194     Widget smartIndentW;
195     Widget defaultWrapW;
196     Widget noWrapW;
197     Widget newlineWrapW;
198     Widget contWrapW;
199     languageModeRec **languageModeList;
200     int nLanguageModes;
201 } LMDialog = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
202               NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0};
203 
204 /* Font dialog information */
205 typedef struct {
206     Widget shell;
207     Widget primaryW;
208     Widget fillW;
209     Widget italicW;
210     Widget italicErrW;
211     Widget boldW;
212     Widget boldErrW;
213     Widget boldItalicW;
214     Widget boldItalicErrW;
215     WindowInfo *window;
216     int forWindow;
217 } fontDialog;
218 
219 /* Color dialog information */
220 typedef struct {
221     Widget shell;
222     Widget textFgW;
223     Widget textFgErrW;
224     Widget textBgW;
225     Widget textBgErrW;
226     Widget selectFgW;
227     Widget selectFgErrW;
228     Widget selectBgW;
229     Widget selectBgErrW;
230     Widget hiliteFgW;
231     Widget hiliteFgErrW;
232     Widget hiliteBgW;
233     Widget hiliteBgErrW;
234     Widget lineNoFgW;
235     Widget lineNoFgErrW;
236     Widget cursorFgW;
237     Widget cursorFgErrW;
238     WindowInfo *window;
239 } colorDialog;
240 
241 /* Repository for simple preferences settings */
242 static struct prefData {
243     int openInTab;		/* open files in new tabs  */
244     int wrapStyle;		/* what kind of wrapping to do */
245     int wrapMargin;		/* 0=wrap at window width, other=wrap margin */
246     int autoIndent;		/* style for auto-indent */
247     int autoSave;		/* whether automatic backup feature is on */
248     int saveOldVersion;		/* whether to preserve a copy of last version */
249     int searchDlogs;		/* whether to show explanatory search dialogs */
250     int searchWrapBeep;     	/* 1=beep when search restarts at begin/end */
251     int keepSearchDlogs;	/* whether to retain find and replace dialogs */
252     int searchWraps;	/* whether to attempt search again if reach bof or eof */
253     int statsLine;		/* whether to show the statistics line */
254     int iSearchLine;	    	/* whether to show the incremental search line*/
255     int tabBar;			/* whether to show the tab bar */
256     int tabBarHideOne;		/* hide tab bar if only one document in window */
257     int globalTabNavigate;  	/* prev/next document across windows */
258     int toolTips;	    	/* whether to show the tooltips */
259     int lineNums;   	    	/* whether to show line numbers */
260     int pathInWindowsMenu;   	/* whether to show path in windows menu */
261     int warnFileMods;	    	/* warn user if files externally modified */
262     int warnRealFileMods;	/* only warn if file contents modified */
263     int warnExit;	    	/* whether to warn on exit */
264     int searchMethod;		/* initial search method as a text string */
265 #ifdef REPLACE_SCOPE
266     int replaceDefScope;	/* default replace scope if selection exists */
267 #endif
268     int textRows;		/* initial window height in characters */
269     int textCols;		/* initial window width in characters */
270     int tabDist;		/* number of characters between tab stops */
271     int emTabDist;		/* non-zero tab dist. if emulated tabs are on */
272     int insertTabs;		/* whether to use tabs for padding */
273     int showMatchingStyle;	/* how to flash matching parenthesis */
274     int matchSyntaxBased;	/* use syntax info to match parenthesis */
275     int highlightSyntax;    	/* whether to highlight syntax by default */
276     int smartTags;  	    	/* look for tag in current window first */
277     int alwaysCheckRelativeTagsSpecs; /* for every new opened file of session */
278     int stickyCaseSenseBtn;     /* whether Case Word Btn is sticky to Regex Btn */
279     int prefFileRead;	    	/* detects whether a .nedit existed */
280     int backlightChars;		/* whether to apply character "backlighting" */
281     char *backlightCharTypes;	/* the backlighting color definitions */
282 #ifdef SGI_CUSTOM
283     int shortMenus; 	    	/* short menu mode */
284 #endif
285     char fontString[MAX_FONT_LEN]; /* names of fonts for text widget */
286     char boldFontString[MAX_FONT_LEN];
287     char italicFontString[MAX_FONT_LEN];
288     char boldItalicFontString[MAX_FONT_LEN];
289     XmFontList fontList;	/* XmFontLists corresp. to above named fonts */
290     XFontStruct *boldFontStruct;
291     XFontStruct *italicFontStruct;
292     XFontStruct *boldItalicFontStruct;
293     int sortTabs;		/* sort tabs alphabetically */
294     int repositionDialogs;	/* w. to reposition dialogs under the pointer */
295     int autoScroll;             /* w. to autoscroll near top/bottom of screen */
296     int autoScrollVPadding;     /* how close to get before autoscrolling */
297     int sortOpenPrevMenu;   	/* whether to sort the "Open Previous" menu */
298     int appendLF;       /* Whether to append LF at the end of each file */
299     int mapDelete;		/* whether to map delete to backspace */
300     int stdOpenDialog;		/* w. to retain redundant text field in Open */
301     char tagFile[MAXPATHLEN];	/* name of tags file to look for at startup */
302     int maxPrevOpenFiles;   	/* limit to size of Open Previous menu */
303     int typingHidesPointer;     /* hide mouse pointer when typing */
304     char delimiters[MAX_WORD_DELIMITERS]; /* punctuation characters */
305     char shell[MAXPATHLEN + 1]; /* shell to use for executing commands */
306     char geometry[MAX_GEOM_STRING_LEN];	/* per-application geometry string,
307     	    	    	    	    	   only for the clueless */
308     char serverName[MAXPATHLEN];/* server name for multiple servers per disp. */
309     char bgMenuBtn[MAX_ACCEL_LEN]; /* X event description for triggering
310     	    	    	    	      posting of background menu */
311     char fileVersion[6]; 	/* Version of nedit which wrote the .nedit
312     				   file we're reading */
313     int findReplaceUsesSelection; /* whether the find replace dialog is automatically
314                                      loaded with the primary selection */
315     int virtKeyOverride;	/* Override Motif default virtual key bindings
316 				   never, if invalid, or always */
317     char titleFormat[MAX_TITLE_FORMAT_LEN];
318     char helpFontNames[NUM_HELP_FONTS][MAX_FONT_LEN];/* fonts for help system */
319     char helpLinkColor[MAX_COLOR_LEN]; 	/* Color for hyperlinks in the help system */
320     char colorNames[NUM_COLORS][MAX_COLOR_LEN];
321     char tooltipBgColor[MAX_COLOR_LEN];
322     int  undoModifiesSelection;
323     int  focusOnRaise;
324     Boolean honorSymlinks;
325     int truncSubstitution;
326     Boolean forceOSConversion;
327 } PrefData;
328 
329 /* Temporary storage for preferences strings which are discarded after being
330    read */
331 static struct {
332     char *shellCmds;
333     char *macroCmds;
334     char *bgMenuCmds;
335     char *highlight;
336     char *language;
337     char *styles;
338     char *smartIndent;
339     char *smartIndentCommon;
340     char *shell;
341 } TempStringPrefs;
342 
343 /* preference descriptions for SavePreferences and RestorePreferences. */
344 static PrefDescripRec PrefDescrip[] = {
345     {"fileVersion", "FileVersion" , PREF_STRING, "", PrefData.fileVersion,
346       (void *)sizeof(PrefData.fileVersion), True},
347 #ifndef VMS
348 #ifdef linux
349     {"shellCommands", "ShellCommands", PREF_ALLOC_STRING, "spell:Alt+B:s:EX:\n\
350     cat>spellTmp; xterm -e ispell -x spellTmp; cat spellTmp; rm spellTmp\n\
351     wc::w:ED:\nwc | awk '{print $1 \" lines, \" $2 \" words, \" $3 \" characters\"}'\n\
352     sort::o:EX:\nsort\nnumber lines::n:AW:\nnl -ba\nmake:Alt+Z:m:W:\nmake\n\
353     expand::p:EX:\nexpand\nunexpand::u:EX:\nunexpand\n",
354     &TempStringPrefs.shellCmds, NULL, True},
355 #elif __FreeBSD__
356     {"shellCommands", "ShellCommands", PREF_ALLOC_STRING, "spell:Alt+B:s:EX:\n\
357     cat>spellTmp; xterm -e ispell -x spellTmp; cat spellTmp; rm spellTmp\n\
358     wc::w:ED:\nwc | awk '{print $2 \" lines, \" $1 \" words, \" $3 \" characters\"}'\n\
359     sort::o:EX:\nsort\nnumber lines::n:AW:\npr -tn\nmake:Alt+Z:m:W:\nmake\n\
360     expand::p:EX:\nexpand\nunexpand::u:EX:\nunexpand\n",
361     &TempStringPrefs.shellCmds, NULL, True},
362 #else
363     {"shellCommands", "ShellCommands", PREF_ALLOC_STRING, "spell:Alt+B:s:ED:\n\
364     (cat;echo \"\") | spell\nwc::w:ED:\nwc | awk '{print $1 \" lines, \" $2 \" words, \" $3 \" characters\"}'\n\
365     \nsort::o:EX:\nsort\nnumber lines::n:AW:\nnl -ba\nmake:Alt+Z:m:W:\nmake\n\
366     expand::p:EX:\nexpand\nunexpand::u:EX:\nunexpand\n",
367     &TempStringPrefs.shellCmds, NULL, True},
368 #endif /* linux, __FreeBSD__ */
369 #endif /* VMS */
370     {"macroCommands", "MacroCommands", PREF_ALLOC_STRING,
371 	"Complete Word:Alt+D::: {\n\
372 		# This macro attempts to complete the current word by\n\
373 		# finding another word in the same document that has\n\
374 		# the same prefix; repeated invocations of the macro\n\
375 		# (by repeated typing of its accelerator, say) cycles\n\
376 		# through the alternatives found.\n\
377 		# \n\
378 		# Make sure $compWord contains something (a dummy index)\n\
379 		$compWord[\"\"] = \"\"\n\
380 		\n\
381 		# Test whether the rest of $compWord has been initialized:\n\
382 		# this avoids having to initialize the global variable\n\
383 		# $compWord in an external macro file\n\
384 		if (!(\"wordEnd\" in $compWord)) {\n\
385 		    # we need to initialize it\n\
386 		    $compWord[\"wordEnd\"] = 0\n\
387 		    $compWord[\"repeat\"] = 0\n\
388 		    $compWord[\"init\"] = 0\n\
389 		    $compWord[\"wordStart\"] = 0\n\
390 		}\n\
391 		\n\
392 		if ($compWord[\"wordEnd\"] == $cursor) {\n\
393 		        $compWord[\"repeat\"] += 1\n\
394 		}\n\
395 		else {\n\
396 		   $compWord[\"repeat\"] = 1\n\
397 		   $compWord[\"init\"] = $cursor\n\
398 		\n\
399 		   # search back to a word boundary to find the word to complete\n\
400 		   # (we use \\w here to allow for programming \"words\" that can include\n\
401 		   # digits and underscores; use \\l for letters only)\n\
402 		   $compWord[\"wordStart\"] = search(\"<\\\\w+\", $cursor, \"backward\", \"regex\", \"wrap\")\n\
403 		\n\
404 		   if ($compWord[\"wordStart\"] == -1)\n\
405 		      return\n\
406 		\n\
407 		    if ($search_end == $cursor)\n\
408 		       $compWord[\"word\"] = get_range($compWord[\"wordStart\"], $cursor)\n\
409 		    else\n\
410 		        return\n\
411 		}\n\
412 		s = $cursor\n\
413 		for (i=0; i <= $compWord[\"repeat\"]; i++)\n\
414 		    s = search($compWord[\"word\"], s - 1, \"backward\", \"regex\", \"wrap\")\n\
415 		\n\
416 		if (s == $compWord[\"wordStart\"]) {\n\
417 		   beep()\n\
418 		   $compWord[\"repeat\"] = 0\n\
419 		   s = $compWord[\"wordStart\"]\n\
420 		   se = $compWord[\"init\"]\n\
421 		}\n\
422 		else\n\
423 		   se = search(\">\", s, \"regex\")\n\
424 		\n\
425 		replace_range($compWord[\"wordStart\"], $cursor, get_range(s, se))\n\
426 		\n\
427 		$compWord[\"wordEnd\"] = $cursor\n\
428 	}\n\
429 	Fill Sel. w/Char:::R: {\n\
430 		# This macro replaces each character position in\n\
431 		# the selection with the string typed into the dialog\n\
432 		# it displays.\n\
433 		if ($selection_start == -1) {\n\
434 		    beep()\n\
435 		    return\n\
436 		}\n\
437 		\n\
438 		# Ask the user what character to fill with\n\
439 		fillChar = string_dialog(\"Fill selection with what character?\", \\\n\
440 		                         \"OK\", \"Cancel\")\n\
441 		if ($string_dialog_button == 2 || $string_dialog_button == 0)\n\
442 		    return\n\
443 		\n\
444 		# Count the number of lines (NL characters) in the selection\n\
445 		# (by removing all non-NLs in selection and counting the remainder)\n\
446 		nLines = length(replace_in_string(get_selection(), \\\n\
447 		                                  \"^.*$\", \"\", \"regex\"))\n\
448 		\n\
449 		rectangular = $selection_left != -1\n\
450 		\n\
451 		# work out the pieces of required of the replacement text\n\
452 		# this will be top mid bot where top is empty or ends in NL,\n\
453 		# mid is 0 or more lines of repeats ending with NL, and\n\
454 		# bot is 0 or more repeats of the fillChar\n\
455 		\n\
456 		toplen = -1 # top piece by default empty (no NL)\n\
457 		midlen = 0\n\
458 		botlen = 0\n\
459 		\n\
460 		if (rectangular) {\n\
461 		    # just fill the rectangle:  mid\\n \\ nLines\n\
462 		    #                           mid\\n /\n\
463 		    #                           bot   - last line with no nl\n\
464 		    midlen = $selection_right -  $selection_left\n\
465 		    botlen = $selection_right -  $selection_left\n\
466 		} else {\n\
467 		    #                  |col[0]\n\
468 		    #         .........toptoptop\\n                      |col[0]\n\
469 		    # either  midmidmidmidmidmid\\n \\ nLines - 1   or ...botbot...\n\
470 		    #         midmidmidmidmidmid\\n /                          |col[1]\n\
471 		    #         botbot...         |\n\
472 		    #                 |col[1]   |wrap margin\n\
473 		    # we need column positions col[0], col[1] of selection start and\n\
474 		    # end (use a loop and arrays to do the two positions)\n\
475 		    sel[0] = $selection_start\n\
476 		    sel[1] = $selection_end\n\
477 		\n\
478 		    # col[0] = pos_to_column($selection_start)\n\
479 		    # col[1] = pos_to_column($selection_end)\n\
480 		\n\
481 		    for (i = 0; i < 2; ++i) {\n\
482 		        end = sel[i]\n\
483 		        pos = search(\"^\", end, \"regex\", \"backward\")\n\
484 		        thisCol = 0\n\
485 		        while (pos < end) {\n\
486 		            nexttab = search(\"\\t\", pos)\n\
487 		            if (nexttab < 0 || nexttab >= end) {\n\
488 		                thisCol += end - pos # count remaining non-tabs\n\
489 		                nexttab = end\n\
490 		            } else {\n\
491 		                thisCol += nexttab - pos + $tab_dist\n\
492 		                thisCol -= (thisCol % $tab_dist)\n\
493 		            }\n\
494 		            pos = nexttab + 1 # skip past the tab or end\n\
495 		        }\n\
496 		        col[i] = thisCol\n\
497 		    }\n\
498 		    toplen = max($wrap_margin - col[0], 0)\n\
499 		    botlen = min(col[1], $wrap_margin)\n\
500 		\n\
501 		    if (nLines == 0) {\n\
502 		        toplen = -1\n\
503 		        botlen = max(botlen - col[0], 0)\n\
504 		    } else {\n\
505 		        midlen = $wrap_margin\n\
506 		        if (toplen < 0)\n\
507 		            toplen = 0\n\
508 		        nLines-- # top piece will end in a NL\n\
509 		    }\n\
510 		}\n\
511 		\n\
512 		# Create the fill text\n\
513 		# which is the longest piece? make a line of that length\n\
514 		# (use string doubling - this allows the piece to be\n\
515 		# appended to double in size at each iteration)\n\
516 		\n\
517 		len = max(toplen, midlen, botlen)\n\
518 		charlen = length(fillChar) # maybe more than one char given!\n\
519 		\n\
520 		line = \"\"\n\
521 		while (len > 0) {\n\
522 		    if (len % 2)\n\
523 		        line = line fillChar\n\
524 		    len /= 2\n\
525 		    if (len > 0)\n\
526 		        fillChar = fillChar fillChar\n\
527 		}\n\
528 		# assemble our pieces\n\
529 		toppiece = \"\"\n\
530 		midpiece = \"\"\n\
531 		botpiece = \"\"\n\
532 		if (toplen >= 0)\n\
533 		    toppiece = substring(line, 0, toplen * charlen) \"\\n\"\n\
534 		if (botlen > 0)\n\
535 		    botpiece = substring(line, 0, botlen * charlen)\n\
536 		\n\
537 		# assemble midpiece (use doubling again)\n\
538 		line = substring(line, 0, midlen * charlen) \"\\n\"\n\
539 		while (nLines > 0) {\n\
540 		    if (nLines % 2)\n\
541 		        midpiece = midpiece line\n\
542 		    nLines /= 2\n\
543 		    if (nLines > 0)\n\
544 		        line = line line\n\
545 		}\n\
546 		# Replace the selection with the complete fill text\n\
547 		replace_selection(toppiece midpiece botpiece)\n\
548 	}\n\
549 	Quote Mail Reply:::: {\n\
550 		if ($selection_start == -1)\n\
551 		    replace_all(\"^.*$\", \"\\\\> &\", \"regex\")\n\
552 		else\n\
553 		    replace_in_selection(\"^.*$\", \"\\\\> &\", \"regex\")\n\
554 	}\n\
555 	Unquote Mail Reply:::: {\n\
556 		if ($selection_start == -1)\n\
557 		    replace_all(\"(^\\\\> )(.*)$\", \"\\\\2\", \"regex\")\n\
558 		else\n\
559 		    replace_in_selection(\"(^\\\\> )(.*)$\", \"\\\\2\", \"regex\")\n\
560 	}\n\
561 	Comments>/* Comment */@C@C++@Java@CSS@JavaScript@Lex:::R: {\n\
562 		selStart = $selection_start\n\
563 		selEnd = $selection_end\n\
564 		replace_range(selStart, selEnd, \"/* \" get_selection() \" */\")\n\
565 		select(selStart, selEnd + 6)\n\
566 	}\n\
567 	Comments>/* Uncomment */@C@C++@Java@CSS@JavaScript@Lex:::R: {\n\
568 		pos = search(\"(?n\\\\s*/\\\\*\\\\s*)\", $selection_start, \"regex\")\n\
569 		start = $search_end\n\
570 		end = search(\"(?n\\\\*/\\\\s*)\", $selection_end, \"regex\", \"backward\")\n\
571 		if (pos != $selection_start || end == -1 )\n\
572 		    return\n\
573 		replace_selection(get_range(start, end))\n\
574 		select(pos, $cursor)\n\
575 	}\n\
576 	Comments>// Comment@C@C++@Java@JavaScript:::R: {\n\
577 		replace_in_selection(\"^.*$\", \"// &\", \"regex\")\n\
578 	}\n\
579 	Comments>// Uncomment@C@C++@Java@JavaScript:::R: {\n\
580 		replace_in_selection(\"(^[ \\\\t]*// ?)(.*)$\", \"\\\\2\", \"regex\")\n\
581 	}\n\
582 	Comments># Comment@Perl@Sh Ksh Bash@NEdit Macro@Makefile@Awk@Csh@Python@Tcl:::R: {\n\
583 		replace_in_selection(\"^.*$\", \"#&\", \"regex\")\n\
584 	}\n\
585 	Comments># Uncomment@Perl@Sh Ksh Bash@NEdit Macro@Makefile@Awk@Csh@Python@Tcl:::R: {\n\
586 		replace_in_selection(\"(^[ \\\\t]*#)(.*)$\", \"\\\\2\", \"regex\")\n\
587 	}\n\
588 	Comments>-- Comment@SQL:::R: {\n\
589 		replace_in_selection(\"^.*$\", \"--&\", \"regex\")\n\
590 	}\n\
591 	Comments>-- Uncomment@SQL:::R: {\n\
592 		replace_in_selection(\"(^[ \\\\t]*--)(.*)$\", \"\\\\2\", \"regex\")\n\
593 	}\n\
594 	Comments>! Comment@X Resources:::R: {\n\
595 		replace_in_selection(\"^.*$\", \"!&\", \"regex\")\n\
596 	}\n\
597 	Comments>! Uncomment@X Resources:::R: {\n\
598 		replace_in_selection(\"(^[ \\\\t]*!)(.*)$\", \"\\\\2\", \"regex\")\n\
599 	}\n\
600 	Comments>% Comment@LaTeX:::R: {\n\
601 		replace_in_selection(\"^.*$\", \"%&\", \"regex\")\n\
602 		}\n\
603 	Comments>% Uncomment@LaTeX:::R: {\n\
604 		replace_in_selection(\"(^[ \\\\t]*%)(.*)$\", \"\\\\2\", \"regex\")\n\
605 		}\n\
606 	Comments>Bar Comment@C:::R: {\n\
607 		if ($selection_left != -1) {\n\
608 		    dialog(\"Selection must not be rectangular\")\n\
609 		    return\n\
610 		}\n\
611 		start = $selection_start\n\
612 		end = $selection_end-1\n\
613 		origText = get_range($selection_start, $selection_end-1)\n\
614 		newText = \"/*\\n\" replace_in_string(get_range(start, end), \\\n\
615 		    \"^\", \" * \", \"regex\") \"\\n */\\n\"\n\
616 		replace_selection(newText)\n\
617 		select(start, start + length(newText))\n\
618 	}\n\
619 	Comments>Bar Uncomment@C:::R: {\n\
620 		selStart = $selection_start\n\
621 		selEnd = $selection_end\n\
622 		pos = search(\"/\\\\*\\\\s*\\\\n\", selStart, \"regex\")\n\
623 		if (pos != selStart) return\n\
624 		start = $search_end\n\
625 		end = search(\"\\\\n\\\\s*\\\\*/\\\\s*\\\\n?\", selEnd, \"regex\", \"backward\")\n\
626 		if (end == -1 || $search_end < selEnd) return\n\
627 		newText = get_range(start, end)\n\
628 		newText = replace_in_string(newText,\"^ *\\\\* ?\", \"\", \"regex\", \"copy\")\n\
629 		if (get_range(selEnd, selEnd - 1) == \"\\n\") selEnd -= 1\n\
630 		replace_range(selStart, selEnd, newText)\n\
631 		select(selStart, selStart + length(newText))\n\
632 	}\n\
633 	Make C Prototypes@C@C++:::: {\n\
634 		# simplistic extraction of C function prototypes, usually good enough\n\
635 		if ($selection_start == -1) {\n\
636 		    start = 0\n\
637 		    end = $text_length\n\
638 		} else {\n\
639 		    start = $selection_start\n\
640 		    end = $selection_end\n\
641 		}\n\
642 		string = get_range(start, end)\n\
643 		# remove all C++ and C comments, then all blank lines in the extracted range\n\
644 		string = replace_in_string(string, \"//.*$\", \"\", \"regex\", \"copy\")\n\
645 		string = replace_in_string(string, \"(?n/\\\\*.*?\\\\*/)\", \"\", \"regex\", \"copy\")\n\
646 		string = replace_in_string(string, \"^\\\\s*\\n\", \"\", \"regex\", \"copy\")\n\
647 		nDefs = 0\n\
648 		searchPos = 0\n\
649 		prototypes = \"\"\n\
650 		staticPrototypes = \"\"\n\
651 		for (;;) {\n\
652 		    headerStart = search_string(string, \\\n\
653 		        \"^[a-zA-Z]([^;#\\\"'{}=><!/]|\\n)*\\\\)[ \\t]*\\n?[ \\t]*\\\\{\", \\\n\
654 		        searchPos, \"regex\")\n\
655 		    if (headerStart == -1)\n\
656 		        break\n\
657 		    headerEnd = search_string(string, \")\", $search_end,\"backward\") + 1\n\
658 		    prototype = substring(string, headerStart, headerEnd) \";\\n\"\n\
659 		    if (substring(string, headerStart, headerStart+6) == \"static\")\n\
660 		        staticPrototypes = staticPrototypes prototype\n\
661 		    else\n\
662 		        prototypes = prototypes prototype\n\
663 		    searchPos = headerEnd\n\
664 		    nDefs++\n\
665 		}\n\
666 		if (nDefs == 0) {\n\
667 		    dialog(\"No function declarations found\")\n\
668 		    return\n\
669 		}\n\
670 		new()\n\
671 		focus_window(\"last\")\n\
672 		replace_range(0, 0, prototypes staticPrototypes)\n\
673 	}", &TempStringPrefs.macroCmds, NULL, True},
674     {"bgMenuCommands", "BGMenuCommands", PREF_ALLOC_STRING,
675        "Undo:::: {\nundo()\n}\n\
676 	Redo:::: {\nredo()\n}\n\
677 	Cut:::R: {\ncut_clipboard()\n}\n\
678 	Copy:::R: {\ncopy_clipboard()\n}\n\
679 	Paste:::: {\npaste_clipboard()\n}", &TempStringPrefs.bgMenuCmds,
680 	NULL, True},
681 #ifdef VMS
682 /* The VAX compiler can't compile Java-Script's definition in highlightData.c */
683     {"highlightPatterns", "HighlightPatterns", PREF_ALLOC_STRING,
684        "Ada:Default\n\
685         Awk:Default\n\
686         C++:Default\n\
687         C:Default\n\
688         CSS:Default\n\
689         Csh:Default\n\
690         Fortran:Default\n\
691         Java:Default\n\
692         LaTeX:Default\n\
693         Lex:Default\n\
694         Makefile:Default\n\
695         Matlab:Default\n\
696         NEdit Macro:Default\n\
697         Pascal:Default\n\
698         Perl:Default\n\
699         PostScript:Default\n\
700         Python:Default\n\
701         Regex:Default\n\
702         SGML HTML:Default\n\
703         SQL:Default\n\
704         Sh Ksh Bash:Default\n\
705         Tcl:Default\n\
706         VHDL:Default\n\
707         Verilog:Default\n\
708         XML:Default\n\
709         X Resources:Default\n\
710         Yacc:Default",
711         &TempStringPrefs.highlight, NULL, True},
712     {"languageModes", "LanguageModes", PREF_ALLOC_STRING,
713 #else
714     {"highlightPatterns", "HighlightPatterns", PREF_ALLOC_STRING,
715        "Ada:Default\n\
716         Awk:Default\n\
717         C++:Default\n\
718         C:Default\n\
719         CSS:Default\n\
720         Csh:Default\n\
721         Fortran:Default\n\
722         Java:Default\n\
723         JavaScript:Default\n\
724         LaTeX:Default\n\
725         Lex:Default\n\
726         Makefile:Default\n\
727         Matlab:Default\n\
728         NEdit Macro:Default\n\
729         Pascal:Default\n\
730         Perl:Default\n\
731         PostScript:Default\n\
732         Python:Default\n\
733         Regex:Default\n\
734         SGML HTML:Default\n\
735         SQL:Default\n\
736         Sh Ksh Bash:Default\n\
737         Tcl:Default\n\
738         VHDL:Default\n\
739         Verilog:Default\n\
740         XML:Default\n\
741         X Resources:Default\n\
742         Yacc:Default",
743         &TempStringPrefs.highlight, NULL, True},
744     {"languageModes", "LanguageModes", PREF_ALLOC_STRING,
745 #endif /*VMS*/
746 #ifdef VMS
747 /*  TODO: Some tests indicate that these have to be upper case, but what about
748     the PostScript pattern then? How does VMS handle caseness anyway?  */
749        "Ada:.ADA .AD .ADS .ADB .A:::::::\n\
750         Awk:.AWK:::::::\n\
751         C++:.CC .HH .C .H .I .CXX .HXX .CPP::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\":\n\
752         C:.C .H::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\":\n\
753         CSS:CSS::Auto:None:::\".,/\\`'!|@#%^&*()=+{}[]\"\":;<>?~\":\n\
754         Csh:.CSH .CSHRC .TCSHRC .LOGIN .LOGOUT:\"^[ \\t]*#[ \\t]*![ \\t]*/bin/t?csh\"::::::\n\
755         Fortran:.F .F77 .FOR:::::::\n\
756         Java:.JAVA:::::::\n\
757         LaTeX:.TEX .STY .CLS .LTX .INS .CLO .FD:::::::\n\
758         Lex:.LEX:::::::\n\
759         Makefile:MAKEFILE:::None:8:8::\n\
760         Matlab:.M .OCT .SCI:::::::\n\
761         NEdit Macro:.NM .NEDITMACRO:::::::\n\
762         Pascal:.PAS .P .INT:::::::\n\
763         Perl:.PL .PM .P5:\"^[ \\t]*#[ \\t]*!.*perl\":Auto:None:::\".,/\\\\`'!$@#%^&*()-=+{}[]\"\":;<>?~|\":\n\
764         PostScript:.ps .PS .eps .EPS .epsf .epsi:\"^%!\":::::\"/%(){}[]<>\":\n\
765         Python:.PY:\"^#!.*python\":Auto:None:::\"!\"\"#$%&'()*+,-./:;<=>?@[\\\\]^`{|}~\":\n\
766         Regex:.REG .REGEX:\"\\(\\?[:#=!iInN].+\\)\":None:Continuous::::\n\
767         SGML HTML:.SGML .SGM .HTML .HTM:\"\\<[Hh][Tt][Mm][Ll]\\>\"::::::\n\
768         SQL:.SQL:::::::\n\
769         Sh Ksh Bash:.SH .BASH .KSH .PROFILE .BASHRC .BASH_LOGOUT .BASH_LOGIN .BASH_PROFILE:\"^[ \\t]*#[ \\t]*![ \\t]*/.*bin/(bash|ksh|sh|zsh)\"::::::\n\
770         Tcl:.TCL::Smart:None::::\n\
771         VHDL:.VHD .VHDL .VDL:::::::\n\
772         Verilog:.V:::::::\n\
773         XML:.XML .XSL .DTD:\"\\<(?i\\?xml|!doctype)\"::None:::\"<>/=\"\"'()+*?|\":\n\
774         X Resources:.XRESOURCES .XDEFAULTS .NEDIT .PATS NEDIT.RC:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n\
775         Yacc:.Y::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\":",
776 #else
777        "Ada:.ada .ad .ads .adb .a:::::::\n\
778         Awk:.awk:::::::\n\
779         C++:.cc .hh .C .H .i .cxx .hxx .cpp .c++::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\":\n\
780         C:.c .h::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\":\n\
781         CSS:css::Auto:None:::\".,/\\`'!|@#%^&*()=+{}[]\"\":;<>?~\":\n\
782         Csh:.csh .cshrc .tcshrc .login .logout:\"^[ \\t]*#[ \\t]*![ \\t]*/bin/t?csh\"::::::\n\
783         Fortran:.f .f77 .for:::::::\n\
784         Java:.java:::::::\n\
785         JavaScript:.js:::::::\n\
786         LaTeX:.tex .sty .cls .ltx .ins .clo .fd:::::::\n\
787         Lex:.lex:::::::\n\
788         Makefile:Makefile makefile .gmk:::None:8:8::\n\
789         Matlab:.m .oct .sci:::::::\n\
790         NEdit Macro:.nm .neditmacro:::::::\n\
791         Pascal:.pas .p .int:::::::\n\
792         Perl:.pl .pm .p5 .PL:\"^[ \\t]*#[ \\t]*!.*perl\":Auto:None:::\".,/\\\\`'!$@#%^&*()-=+{}[]\"\":;<>?~|\":\n\
793         PostScript:.ps .eps .epsf .epsi:\"^%!\":::::\"/%(){}[]<>\":\n\
794         Python:.py:\"^#!.*python\":Auto:None:::\"!\"\"#$%&'()*+,-./:;<=>?@[\\\\]^`{|}~\":\n\
795         Regex:.reg .regex:\"\\(\\?[:#=!iInN].+\\)\":None:Continuous::::\n\
796         SGML HTML:.sgml .sgm .html .htm:\"\\<[Hh][Tt][Mm][Ll]\\>\"::::::\n\
797         SQL:.sql:::::::\n\
798         Sh Ksh Bash:.sh .bash .ksh .profile .bashrc .bash_logout .bash_login .bash_profile:\"^[ \\t]*#[ \\t]*![ \\t]*/.*bin/(bash|ksh|sh|zsh)\"::::::\n\
799         Tcl:.tcl .tk .itcl .itk::Smart:None::::\n\
800         VHDL:.vhd .vhdl .vdl:::::::\n\
801         Verilog:.v:::::::\n\
802         XML:.xml .xsl .dtd:\"\\<(?i\\?xml|!doctype)\"::None:::\"<>/=\"\"'()+*?|\":\n\
803         X Resources:.Xresources .Xdefaults .nedit .pats nedit.rc:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n\
804         Yacc:.y::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\":",
805 #endif
806 	&TempStringPrefs.language, NULL, True},
807     {"styles", "Styles", PREF_ALLOC_STRING, "Plain:black:Plain\n\
808     	Comment:gray20:Italic\n\
809     	Keyword:black:Bold\n\
810         Operator:dark blue:Bold\n\
811         Bracket:dark blue:Bold\n\
812     	Storage Type:brown:Bold\n\
813     	Storage Type1:saddle brown:Bold\n\
814     	String:darkGreen:Plain\n\
815     	String1:SeaGreen:Plain\n\
816     	String2:darkGreen:Bold\n\
817     	Preprocessor:RoyalBlue4:Plain\n\
818     	Preprocessor1:blue:Plain\n\
819     	Character Const:darkGreen:Plain\n\
820     	Numeric Const:darkGreen:Plain\n\
821     	Identifier:brown:Plain\n\
822     	Identifier1:RoyalBlue4:Plain\n\
823         Identifier2:SteelBlue:Plain\n\
824  	Subroutine:brown:Plain\n\
825 	Subroutine1:chocolate:Plain\n\
826    	Ada Attributes:plum:Bold\n\
827 	Label:red:Italic\n\
828 	Flag:red:Bold\n\
829     	Text Comment:SteelBlue4:Italic\n\
830     	Text Key:VioletRed4:Bold\n\
831 	Text Key1:VioletRed4:Plain\n\
832     	Text Arg:RoyalBlue4:Bold\n\
833     	Text Arg1:SteelBlue4:Bold\n\
834 	Text Arg2:RoyalBlue4:Plain\n\
835     	Text Escape:gray30:Bold\n\
836 	LaTeX Math:darkGreen:Plain\n"
837         ADD_5_2_STYLES,
838 	&TempStringPrefs.styles, NULL, True},
839     {"smartIndentInit", "SmartIndentInit", PREF_ALLOC_STRING,
840         "C:Default\n\
841 	C++:Default\n\
842 	Python:Default\n\
843 	Matlab:Default", &TempStringPrefs.smartIndent, NULL, True},
844     {"smartIndentInitCommon", "SmartIndentInitCommon", PREF_ALLOC_STRING,
845         "Default", &TempStringPrefs.smartIndentCommon, NULL, True},
846     {"autoWrap", "AutoWrap", PREF_ENUM, "Continuous",
847     	&PrefData.wrapStyle, AutoWrapTypes, True},
848     {"wrapMargin", "WrapMargin", PREF_INT, "0",
849     	&PrefData.wrapMargin, NULL, True},
850     {"autoIndent", "AutoIndent", PREF_ENUM, "Auto",
851     	&PrefData.autoIndent, AutoIndentTypes, True},
852     {"autoSave", "AutoSave", PREF_BOOLEAN, "True",
853     	&PrefData.autoSave, NULL, True},
854     {"openInTab", "OpenInTab", PREF_BOOLEAN, "True",
855     	&PrefData.openInTab, NULL, True},
856     {"saveOldVersion", "SaveOldVersion", PREF_BOOLEAN, "False",
857     	&PrefData.saveOldVersion, NULL, True},
858     {"showMatching", "ShowMatching", PREF_ENUM, "Delimiter",
859  	&PrefData.showMatchingStyle, ShowMatchingTypes, True},
860     {"matchSyntaxBased", "MatchSyntaxBased", PREF_BOOLEAN, "True",
861  	&PrefData.matchSyntaxBased, NULL, True},
862     {"highlightSyntax", "HighlightSyntax", PREF_BOOLEAN, "True",
863     	&PrefData.highlightSyntax, NULL, True},
864     {"backlightChars", "BacklightChars", PREF_BOOLEAN, "False",
865       &PrefData.backlightChars, NULL, True},
866     {"backlightCharTypes", "BacklightCharTypes", PREF_ALLOC_STRING,
867       "0-8,10-31,127:red;9:#dedede;32,160-255:#f0f0f0;128-159:orange",
868     /*                     gray87                 gray94                 */
869       &PrefData.backlightCharTypes, NULL, False},
870     {"searchDialogs", "SearchDialogs", PREF_BOOLEAN, "False",
871     	&PrefData.searchDlogs, NULL, True},
872     {"beepOnSearchWrap", "BeepOnSearchWrap", PREF_BOOLEAN, "False",
873       &PrefData.searchWrapBeep, NULL, True},
874     {"retainSearchDialogs", "RetainSearchDialogs", PREF_BOOLEAN, "False",
875     	&PrefData.keepSearchDlogs, NULL, True},
876     {"searchWraps", "SearchWraps", PREF_BOOLEAN, "True",
877     	&PrefData.searchWraps, NULL, True},
878     {"stickyCaseSenseButton", "StickyCaseSenseButton", PREF_BOOLEAN, "True",
879     	&PrefData.stickyCaseSenseBtn, NULL, True},
880 #if XmVersion < 1002 /* Flashing is annoying in 1.1 versions */
881     {"repositionDialogs", "RepositionDialogs", PREF_BOOLEAN, "False",
882     	&PrefData.repositionDialogs, NULL, True},
883 #else
884     {"repositionDialogs", "RepositionDialogs", PREF_BOOLEAN, "True",
885     	&PrefData.repositionDialogs, NULL, True},
886 #endif
887     {"autoScroll", "AutoScroll", PREF_BOOLEAN, "False",
888     	&PrefData.autoScroll, NULL, True},
889     {"autoScrollVPadding", "AutoScrollVPadding", PREF_INT, "4",
890     	&PrefData.autoScrollVPadding, NULL, False},
891     {"appendLF", "AppendLF", PREF_BOOLEAN, "True",
892         &PrefData.appendLF, NULL, True},
893     {"sortOpenPrevMenu", "SortOpenPrevMenu", PREF_BOOLEAN, "True",
894     	&PrefData.sortOpenPrevMenu, NULL, True},
895     {"statisticsLine", "StatisticsLine", PREF_BOOLEAN, "False",
896     	&PrefData.statsLine, NULL, True},
897     {"iSearchLine", "ISearchLine", PREF_BOOLEAN, "False",
898     	&PrefData.iSearchLine, NULL, True},
899     {"sortTabs", "SortTabs", PREF_BOOLEAN, "False",
900     	&PrefData.sortTabs, NULL, True},
901     {"tabBar", "TabBar", PREF_BOOLEAN, "True",
902     	&PrefData.tabBar, NULL, True},
903     {"tabBarHideOne", "TabBarHideOne", PREF_BOOLEAN, "True",
904     	&PrefData.tabBarHideOne, NULL, True},
905     {"toolTips", "ToolTips", PREF_BOOLEAN, "True",
906     	&PrefData.toolTips, NULL, True},
907     {"globalTabNavigate", "GlobalTabNavigate", PREF_BOOLEAN, "False",
908     	&PrefData.globalTabNavigate, NULL, True},
909     {"lineNumbers", "LineNumbers", PREF_BOOLEAN, "False",
910     	&PrefData.lineNums, NULL, True},
911     {"pathInWindowsMenu", "PathInWindowsMenu", PREF_BOOLEAN, "True",
912     	&PrefData.pathInWindowsMenu, NULL, True},
913     {"warnFileMods", "WarnFileMods", PREF_BOOLEAN, "True",
914     	&PrefData.warnFileMods, NULL, True},
915     {"warnRealFileMods", "WarnRealFileMods", PREF_BOOLEAN, "True",
916     	&PrefData.warnRealFileMods, NULL, True},
917     {"warnExit", "WarnExit", PREF_BOOLEAN, "True",
918     	&PrefData.warnExit, NULL, True},
919     {"searchMethod", "SearchMethod", PREF_ENUM, "Literal",
920     	&PrefData.searchMethod, SearchMethodStrings, True},
921 #ifdef REPLACE_SCOPE
922     {"replaceDefaultScope", "ReplaceDefaultScope", PREF_ENUM, "Smart",
923     	&PrefData.replaceDefScope, ReplaceDefScopeStrings, True},
924 #endif
925     {"textRows", "TextRows", PREF_INT, "24",
926     	&PrefData.textRows, NULL, True},
927     {"textCols", "TextCols", PREF_INT, "80",
928     	&PrefData.textCols, NULL, True},
929     {"tabDistance", "TabDistance", PREF_INT, "8",
930     	&PrefData.tabDist, NULL, True},
931     {"emulateTabs", "EmulateTabs", PREF_INT, "0",
932     	&PrefData.emTabDist, NULL, True},
933     {"insertTabs", "InsertTabs", PREF_BOOLEAN, "True",
934     	&PrefData.insertTabs, NULL, True},
935     {"textFont", "TextFont", PREF_STRING,
936     	"-*-courier-medium-r-normal--14-*-*-*-*-iso8859-1",
937     	PrefData.fontString, (void *)sizeof(PrefData.fontString), True},
938     {"boldHighlightFont", "BoldHighlightFont", PREF_STRING,
939     	"-*-courier-bold-r-normal--14-*-*-*-*-iso8859-1",
940     	PrefData.boldFontString, (void *)sizeof(PrefData.boldFontString), True},
941     {"italicHighlightFont", "ItalicHighlightFont", PREF_STRING,
942     	"-*-courier-medium-o-normal--14-*-*-*-*-iso8859-1",
943     	PrefData.italicFontString,
944     	(void *)sizeof(PrefData.italicFontString), True},
945     {"boldItalicHighlightFont", "BoldItalicHighlightFont", PREF_STRING,
946     	"-*-courier-bold-o-normal--14-*-*-*-*-iso8859-1",
947     	PrefData.boldItalicFontString,
948     	(void *)sizeof(PrefData.boldItalicFontString), True},
949     {"helpFont", "HelpFont", PREF_STRING,
950     	"-*-helvetica-medium-r-normal--14-*-*-*-*-iso8859-1",
951 	PrefData.helpFontNames[HELP_FONT],
952 	(void *)sizeof(PrefData.helpFontNames[HELP_FONT]), False},
953     {"boldHelpFont", "BoldHelpFont", PREF_STRING,
954     	"-*-helvetica-bold-r-normal--14-*-*-*-*-iso8859-1",
955 	PrefData.helpFontNames[BOLD_HELP_FONT],
956 	(void *)sizeof(PrefData.helpFontNames[BOLD_HELP_FONT]), False},
957     {"italicHelpFont", "ItalicHelpFont", PREF_STRING,
958     	"-*-helvetica-medium-o-normal--14-*-*-*-*-iso8859-1",
959 	PrefData.helpFontNames[ITALIC_HELP_FONT],
960 	(void *)sizeof(PrefData.helpFontNames[ITALIC_HELP_FONT]), False},
961     {"boldItalicHelpFont", "BoldItalicHelpFont", PREF_STRING,
962     	"-*-helvetica-bold-o-normal--14-*-*-*-*-iso8859-1",
963 	PrefData.helpFontNames[BOLD_ITALIC_HELP_FONT],
964 	(void *)sizeof(PrefData.helpFontNames[BOLD_ITALIC_HELP_FONT]), False},
965     {"fixedHelpFont", "FixedHelpFont", PREF_STRING,
966     	"-*-courier-medium-r-normal--14-*-*-*-*-iso8859-1",
967 	PrefData.helpFontNames[FIXED_HELP_FONT],
968 	(void *)sizeof(PrefData.helpFontNames[FIXED_HELP_FONT]), False},
969     {"boldFixedHelpFont", "BoldFixedHelpFont", PREF_STRING,
970     	"-*-courier-bold-r-normal--14-*-*-*-*-iso8859-1",
971 	PrefData.helpFontNames[BOLD_FIXED_HELP_FONT],
972 	(void *)sizeof(PrefData.helpFontNames[BOLD_FIXED_HELP_FONT]), False},
973     {"italicFixedHelpFont", "ItalicFixedHelpFont", PREF_STRING,
974     	"-*-courier-medium-o-normal--14-*-*-*-*-iso8859-1",
975 	PrefData.helpFontNames[ITALIC_FIXED_HELP_FONT],
976 	(void *)sizeof(PrefData.helpFontNames[ITALIC_FIXED_HELP_FONT]), False},
977     {"boldItalicFixedHelpFont", "BoldItalicFixedHelpFont", PREF_STRING,
978     	"-*-courier-bold-o-normal--14-*-*-*-*-iso8859-1",
979 	PrefData.helpFontNames[BOLD_ITALIC_FIXED_HELP_FONT],
980 	(void *)sizeof(PrefData.helpFontNames[BOLD_ITALIC_FIXED_HELP_FONT]), False},
981     {"helpLinkFont", "HelpLinkFont", PREF_STRING,
982     	"-*-helvetica-medium-r-normal--14-*-*-*-*-iso8859-1",
983 	PrefData.helpFontNames[HELP_LINK_FONT],
984 	(void *)sizeof(PrefData.helpFontNames[HELP_LINK_FONT]), False},
985     {"h1HelpFont", "H1HelpFont", PREF_STRING,
986     	"-*-helvetica-bold-r-normal--*-140-*-*-*-iso8859-1",
987 	PrefData.helpFontNames[H1_HELP_FONT],
988 	(void *)sizeof(PrefData.helpFontNames[H1_HELP_FONT]), False},
989     {"h2HelpFont", "H2HelpFont", PREF_STRING,
990     	"-*-helvetica-bold-o-normal--14-*-*-*-*-iso8859-1",
991 	PrefData.helpFontNames[H2_HELP_FONT],
992 	(void *)sizeof(PrefData.helpFontNames[H2_HELP_FONT]), False},
993     {"h3HelpFont", "H3HelpFont", PREF_STRING,
994     	"-*-courier-bold-r-normal--14-*-*-*-*-iso8859-1",
995 	PrefData.helpFontNames[H3_HELP_FONT],
996 	(void *)sizeof(PrefData.helpFontNames[H3_HELP_FONT]), False},
997     {"helpLinkColor", "HelpLinkColor", PREF_STRING, "#009900",
998 	PrefData.helpLinkColor,
999 	(void *)sizeof(PrefData.helpLinkColor), False},
1000 
1001     {"textFgColor", "TextFgColor", PREF_STRING, NEDIT_DEFAULT_FG,
1002         PrefData.colorNames[TEXT_FG_COLOR],
1003         (void *)sizeof(PrefData.colorNames[TEXT_FG_COLOR]), True},
1004     {"textBgColor", "TextBgColor", PREF_STRING, NEDIT_DEFAULT_TEXT_BG,
1005         PrefData.colorNames[TEXT_BG_COLOR],
1006         (void *)sizeof(PrefData.colorNames[TEXT_BG_COLOR]), True},
1007     {"selectFgColor", "SelectFgColor", PREF_STRING, NEDIT_DEFAULT_SEL_FG,
1008         PrefData.colorNames[SELECT_FG_COLOR],
1009         (void *)sizeof(PrefData.colorNames[SELECT_FG_COLOR]), True},
1010     {"selectBgColor", "SelectBgColor", PREF_STRING, NEDIT_DEFAULT_SEL_BG,
1011         PrefData.colorNames[SELECT_BG_COLOR],
1012         (void *)sizeof(PrefData.colorNames[SELECT_BG_COLOR]), True},
1013     {"hiliteFgColor", "HiliteFgColor", PREF_STRING, NEDIT_DEFAULT_HI_FG,
1014         PrefData.colorNames[HILITE_FG_COLOR],
1015         (void *)sizeof(PrefData.colorNames[HILITE_FG_COLOR]), True},
1016     {"hiliteBgColor", "HiliteBgColor", PREF_STRING, NEDIT_DEFAULT_HI_BG,
1017         PrefData.colorNames[HILITE_BG_COLOR],
1018         (void *)sizeof(PrefData.colorNames[HILITE_BG_COLOR]), True},
1019     {"lineNoFgColor", "LineNoFgColor", PREF_STRING, NEDIT_DEFAULT_LINENO_FG,
1020         PrefData.colorNames[LINENO_FG_COLOR],
1021         (void *)sizeof(PrefData.colorNames[LINENO_FG_COLOR]), True},
1022     {"cursorFgColor", "CursorFgColor", PREF_STRING, NEDIT_DEFAULT_CURSOR_FG,
1023         PrefData.colorNames[CURSOR_FG_COLOR],
1024         (void *)sizeof(PrefData.colorNames[CURSOR_FG_COLOR]), True},
1025     {"tooltipBgColor", "TooltipBgColor", PREF_STRING, "LemonChiffon1",
1026         PrefData.tooltipBgColor,
1027         (void *)sizeof(PrefData.tooltipBgColor), False},
1028     {"shell", "Shell", PREF_STRING, "DEFAULT", PrefData.shell,
1029         (void*) sizeof(PrefData.shell), True},
1030     {"geometry", "Geometry", PREF_STRING, "",
1031     	PrefData.geometry, (void *)sizeof(PrefData.geometry), False},
1032     {"remapDeleteKey", "RemapDeleteKey", PREF_BOOLEAN, "False",
1033     	&PrefData.mapDelete, NULL, False},
1034     {"stdOpenDialog", "StdOpenDialog", PREF_BOOLEAN, "False",
1035     	&PrefData.stdOpenDialog, NULL, False},
1036     {"tagFile", "TagFile", PREF_STRING,
1037     	"", PrefData.tagFile, (void *)sizeof(PrefData.tagFile), False},
1038     {"wordDelimiters", "WordDelimiters", PREF_STRING,
1039     	".,/\\`'!|@#%^&*()-=+{}[]\":;<>?",
1040     	PrefData.delimiters, (void *)sizeof(PrefData.delimiters), False},
1041     {"serverName", "ServerName", PREF_STRING, "", PrefData.serverName,
1042       (void *)sizeof(PrefData.serverName), False},
1043     {"maxPrevOpenFiles", "MaxPrevOpenFiles", PREF_INT, "30",
1044     	&PrefData.maxPrevOpenFiles, NULL, False},
1045     {"bgMenuButton", "BGMenuButton" , PREF_STRING,
1046 	"~Shift~Ctrl~Meta~Alt<Btn3Down>", PrefData.bgMenuBtn,
1047       (void *)sizeof(PrefData.bgMenuBtn), False},
1048     {"smartTags", "SmartTags", PREF_BOOLEAN, "True",
1049     	&PrefData.smartTags, NULL, True},
1050     {"typingHidesPointer", "TypingHidesPointer", PREF_BOOLEAN, "False",
1051         &PrefData.typingHidesPointer, NULL, False},
1052     {"alwaysCheckRelativeTagsSpecs", "AlwaysCheckRelativeTagsSpecs",
1053       	PREF_BOOLEAN, "True", &PrefData.alwaysCheckRelativeTagsSpecs, NULL, False},
1054     {"prefFileRead", "PrefFileRead", PREF_BOOLEAN, "False",
1055     	&PrefData.prefFileRead, NULL, True},
1056 #ifdef SGI_CUSTOM
1057     {"shortMenus", "ShortMenus", PREF_BOOLEAN, "False", &PrefData.shortMenus,
1058       NULL, True},
1059 #endif
1060     {"findReplaceUsesSelection", "FindReplaceUsesSelection", PREF_BOOLEAN, "False",
1061     	&PrefData.findReplaceUsesSelection, NULL, False},
1062     {"overrideDefaultVirtualKeyBindings", "OverrideDefaultVirtualKeyBindings",
1063       PREF_ENUM, "Auto", &PrefData.virtKeyOverride, VirtKeyOverrideModes, False},
1064     {"titleFormat", "TitleFormat", PREF_STRING, "{%c} [%s] %f (%S) - %d",
1065 	PrefData.titleFormat, (void *)sizeof(PrefData.titleFormat), True},
1066     {"undoModifiesSelection", "UndoModifiesSelection", PREF_BOOLEAN,
1067         "True", &PrefData.undoModifiesSelection, NULL, False},
1068     {"focusOnRaise", "FocusOnRaise", PREF_BOOLEAN,
1069             "False", &PrefData.focusOnRaise, NULL, False},
1070     {"forceOSConversion", "ForceOSConversion", PREF_BOOLEAN, "True",
1071             &PrefData.forceOSConversion, NULL, False},
1072     {"truncSubstitution", "TruncSubstitution", PREF_ENUM, "Fail",
1073             &PrefData.truncSubstitution, TruncSubstitutionModes, False},
1074     {"honorSymlinks", "HonorSymlinks", PREF_BOOLEAN, "True",
1075             &PrefData.honorSymlinks, NULL, False}
1076 };
1077 
1078 static XrmOptionDescRec OpTable[] = {
1079     {"-wrap", ".autoWrap", XrmoptionNoArg, (caddr_t)"Continuous"},
1080     {"-nowrap", ".autoWrap", XrmoptionNoArg, (caddr_t)"None"},
1081     {"-autowrap", ".autoWrap", XrmoptionNoArg, (caddr_t)"Newline"},
1082     {"-noautowrap", ".autoWrap", XrmoptionNoArg, (caddr_t)"None"},
1083     {"-autoindent", ".autoIndent", XrmoptionNoArg, (caddr_t)"Auto"},
1084     {"-noautoindent", ".autoIndent", XrmoptionNoArg, (caddr_t)"False"},
1085     {"-autosave", ".autoSave", XrmoptionNoArg, (caddr_t)"True"},
1086     {"-noautosave", ".autoSave", XrmoptionNoArg, (caddr_t)"False"},
1087     {"-rows", ".textRows", XrmoptionSepArg, (caddr_t)NULL},
1088     {"-columns", ".textCols", XrmoptionSepArg, (caddr_t)NULL},
1089     {"-tabs", ".tabDistance", XrmoptionSepArg, (caddr_t)NULL},
1090     {"-font", ".textFont", XrmoptionSepArg, (caddr_t)NULL},
1091     {"-fn", ".textFont", XrmoptionSepArg, (caddr_t)NULL},
1092     {"-svrname", ".serverName", XrmoptionSepArg, (caddr_t)NULL},
1093 };
1094 
1095 static const char HeaderText[] = "\
1096 ! Preferences file for NEdit\n\
1097 ! (User settings in X \"application defaults\" format)\n\
1098 !\n\
1099 ! This file is overwritten by the \"Save Defaults...\" command in NEdit\n\
1100 ! and serves only the interactively settable options presented in the NEdit\n\
1101 ! \"Preferences\" menu.  To modify other options, such as key bindings, use\n\
1102 ! the .Xdefaults file in your home directory (or the X resource\n\
1103 ! specification method appropriate to your system).  The contents of this\n\
1104 ! file can be moved into an X resource file, but since resources in this file\n\
1105 ! override their corresponding X resources, either this file should be \n\
1106 ! deleted or individual resource lines in the file should be deleted for the\n\
1107 ! moved lines to take effect.\n";
1108 
1109 /* Module-global variable set when any preference changes (for asking the
1110    user about re-saving on exit) */
1111 static int PrefsHaveChanged = False;
1112 
1113 /* Module-global variable set when user uses -import to load additional
1114    preferences on top of the defaults.  Contains name of file loaded */
1115 static char *ImportedFile = NULL;
1116 
1117 /* Module-global variables to support Initial Window Size... dialog */
1118 static int DoneWithSizeDialog;
1119 static Widget RowText, ColText;
1120 
1121 /* Module-global variables for Tabs dialog */
1122 static int DoneWithTabsDialog;
1123 static WindowInfo *TabsDialogForWindow;
1124 static Widget TabDistText, EmTabText, EmTabToggle, UseTabsToggle, EmTabLabel;
1125 
1126 /* Module-global variables for Wrap Margin dialog */
1127 static int DoneWithWrapDialog;
1128 static WindowInfo *WrapDialogForWindow;
1129 static Widget WrapText, WrapTextLabel, WrapWindowToggle;
1130 
1131 /*  Module-global variables for shell selection dialog  */
1132 static int DoneWithShellSelDialog = False;
1133 
1134 static void translatePrefFormats(int convertOld, int fileVer);
1135 static void setIntPref(int *prefDataField, int newValue);
1136 static void setStringPref(char *prefDataField, const char *newValue);
1137 static void sizeOKCB(Widget w, XtPointer clientData, XtPointer callData);
1138 static void setStringAllocPref(char **pprefDataField, char *newValue);
1139 static void sizeCancelCB(Widget w, XtPointer clientData, XtPointer callData);
1140 static void tabsOKCB(Widget w, XtPointer clientData, XtPointer callData);
1141 static void tabsCancelCB(Widget w, XtPointer clientData, XtPointer callData);
1142 static void tabsHelpCB(Widget w, XtPointer clientData, XtPointer callData);
1143 static void emTabsCB(Widget w, XtPointer clientData, XtPointer callData);
1144 static void wrapOKCB(Widget w, XtPointer clientData, XtPointer callData);
1145 static void wrapCancelCB(Widget w, XtPointer clientData, XtPointer callData);
1146 static void wrapWindowCB(Widget w, XtPointer clientData, XtPointer callData);
1147 static void shellSelOKCB(Widget widget, XtPointer clientData,
1148         XtPointer callData);
1149 static void shellSelCancelCB(Widget widgget, XtPointer clientData,
1150         XtPointer callData);
1151 static void reapplyLanguageMode(WindowInfo *window, int mode,int forceDefaults);
1152 
1153 static void fillFromPrimaryCB(Widget w, XtPointer clientData,
1154     	XtPointer callData);
1155 static int checkFontStatus(fontDialog *fd, Widget fontTextFieldW);
1156 static int showFontStatus(fontDialog *fd, Widget fontTextFieldW,
1157     	Widget errorLabelW);
1158 static void primaryModifiedCB(Widget w, XtPointer clientData,
1159 	XtPointer callData);
1160 static void italicModifiedCB(Widget w, XtPointer clientData,
1161     	XtPointer callData);
1162 static void boldModifiedCB(Widget w, XtPointer clientData, XtPointer callData);
1163 static void boldItalicModifiedCB(Widget w, XtPointer clientData,
1164     	XtPointer callData);
1165 static void primaryBrowseCB(Widget w, XtPointer clientData, XtPointer callData);
1166 static void italicBrowseCB(Widget w, XtPointer clientData, XtPointer callData);
1167 static void boldBrowseCB(Widget w, XtPointer clientData, XtPointer callData);
1168 static void boldItalicBrowseCB(Widget w, XtPointer clientData,
1169     	XtPointer callData);
1170 static void browseFont(Widget parent, Widget fontTextW);
1171 static void fontDestroyCB(Widget w, XtPointer clientData, XtPointer callData);
1172 static void fontOkCB(Widget w, XtPointer clientData, XtPointer callData);
1173 static void fontApplyCB(Widget w, XtPointer clientData, XtPointer callData);
1174 static void fontCancelCB(Widget w, XtPointer clientData, XtPointer callData);
1175 static void updateFonts(fontDialog *fd);
1176 
1177 static Boolean checkColorStatus(colorDialog *cd, Widget colorFieldW);
1178 static int verifyAllColors (colorDialog *cd);
1179 static void showColorStatus (colorDialog *cd, Widget colorFieldW,
1180       Widget errorLabelW);
1181 static void updateColors(colorDialog *cd);
1182 static void colorDestroyCB(Widget w, XtPointer clientData, XtPointer callData);
1183 static void colorOkCB     (Widget w, XtPointer clientData, XtPointer callData);
1184 static void colorApplyCB  (Widget w, XtPointer clientData, XtPointer callData);
1185 static void colorCloseCB(Widget w, XtPointer clientData, XtPointer callData);
1186 static void textFgModifiedCB  (Widget w, XtPointer clientData,
1187       XtPointer callData);
1188 static void textBgModifiedCB  (Widget w, XtPointer clientData,
1189       XtPointer callData);
1190 static void selectFgModifiedCB(Widget w, XtPointer clientData,
1191         XtPointer callData);
1192 static void selectBgModifiedCB(Widget w, XtPointer clientData,
1193         XtPointer callData);
1194 static void hiliteFgModifiedCB(Widget w, XtPointer clientData,
1195         XtPointer callData);
1196 static void hiliteBgModifiedCB(Widget w, XtPointer clientData,
1197         XtPointer callData);
1198 static void lineNoFgModifiedCB(Widget w, XtPointer clientData,
1199         XtPointer callData);
1200 static void cursorFgModifiedCB(Widget w, XtPointer clientData,
1201         XtPointer callData);
1202 
1203 static int matchLanguageMode(WindowInfo *window);
1204 static int loadLanguageModesString(char *inString, int fileVer);
1205 static char *writeLanguageModesString(void);
1206 static char *createExtString(char **extensions, int nExtensions);
1207 static char **readExtensionList(char **inPtr, int *nExtensions);
1208 static void updateLanguageModeSubmenu(WindowInfo *window);
1209 static void setLangModeCB(Widget w, XtPointer clientData, XtPointer callData);
1210 static int modeError(languageModeRec *lm, const char *stringStart,
1211 	const char *stoppedAt, const char *message);
1212 static void lmDestroyCB(Widget w, XtPointer clientData, XtPointer callData);
1213 static void lmOkCB(Widget w, XtPointer clientData, XtPointer callData);
1214 static void lmApplyCB(Widget w, XtPointer clientData, XtPointer callData);
1215 static void lmCloseCB(Widget w, XtPointer clientData, XtPointer callData);
1216 static int lmDeleteConfirmCB(int itemIndex, void *cbArg);
1217 static int updateLMList(void);
1218 static languageModeRec *copyLanguageModeRec(languageModeRec *lm);
1219 static void *lmGetDisplayedCB(void *oldItem, int explicitRequest, int *abort,
1220     	void *cbArg);
1221 static void lmSetDisplayedCB(void *item, void *cbArg);
1222 static languageModeRec *readLMDialogFields(int silent);
1223 static void lmFreeItemCB(void *item);
1224 static void freeLanguageModeRec(languageModeRec *lm);
1225 static int lmDialogEmpty(void);
1226 static void updatePatternsTo5dot1(void);
1227 static void updatePatternsTo5dot2(void);
1228 static void updatePatternsTo5dot3(void);
1229 static void updatePatternsTo5dot4(void);
1230 static void updateShellCmdsTo5dot3(void);
1231 static void updateShellCmdsTo5dot4(void);
1232 static void updateMacroCmdsTo5dot5(void);
1233 static void updatePatternsTo5dot6(void);
1234 static void updateMacroCmdsTo5dot6(void);
1235 static void migrateColorResources(XrmDatabase prefDB, XrmDatabase appDB);
1236 static void spliceString(char **intoString, const char *insertString, const char *atExpr);
1237 static int regexFind(const char *inString, const char *expr);
1238 static int regexReplace(char **inString, const char *expr,
1239                         const char *replaceWith);
1240 static int caseFind(const char *inString, const char *expr);
1241 static int caseReplace(char **inString, const char *expr,
1242                        const char *replaceWith, int replaceLen);
1243 static int stringReplace(char **inString, const char *expr,
1244                          const char *replaceWith, int searchType,
1245                          int replaceLen);
1246 static int replaceMacroIfUnchanged(const char* oldText, const char* newStart,
1247                                     const char* newEnd);
1248 static const char* getDefaultShell(void);
1249 
1250 
1251 #ifdef SGI_CUSTOM
1252 static int shortPrefToDefault(Widget parent, const char *settingName, int *setDefault);
1253 #endif
1254 
CreateNEditPrefDB(int * argcInOut,char ** argvInOut)1255 XrmDatabase CreateNEditPrefDB(int *argcInOut, char **argvInOut)
1256 {
1257     return CreatePreferencesDatabase(GetRCFileName(NEDIT_RC), APP_NAME,
1258             OpTable, XtNumber(OpTable), (unsigned int *)argcInOut, argvInOut);
1259 }
1260 
RestoreNEditPrefs(XrmDatabase prefDB,XrmDatabase appDB)1261 void RestoreNEditPrefs(XrmDatabase prefDB, XrmDatabase appDB)
1262 {
1263     int requiresConversion;
1264     int major;              /* The integral part of version number */
1265     int minor;              /* fractional part of version number */
1266     int fileVer = 0;        /* Both combined into an integer */
1267     int nparsed;
1268 
1269     /* Load preferences */
1270     RestorePreferences(prefDB, appDB, APP_NAME,
1271     	    APP_CLASS, PrefDescrip, XtNumber(PrefDescrip));
1272 
1273     /* If the preferences file was written by an older version of NEdit,
1274        warn the user that it will be converted. */
1275     requiresConversion = PrefData.prefFileRead &&
1276     	    PrefData.fileVersion[0] == '\0';
1277     if (requiresConversion) {
1278 	updatePatternsTo5dot1();
1279     }
1280 
1281     if (PrefData.prefFileRead) {
1282         if (PrefData.fileVersion[0] == '\0') {
1283             fileVer = 0;    /* Pre-5.1 */
1284         }
1285         else {
1286             /* Note: do not change the format of this.  Older executables
1287                need to read this field for forward compatability. */
1288             nparsed = sscanf(PrefData.fileVersion, "%d.%d", &major, &minor);
1289             if (nparsed >= 2) {
1290                 /* Use OSF-style numbering scheme */
1291                 fileVer = major * 1000 + minor;
1292             }
1293         }
1294     }
1295 
1296     if (PrefData.prefFileRead && fileVer < 5002) {
1297         updatePatternsTo5dot2();
1298     }
1299 
1300     if (PrefData.prefFileRead && fileVer < 5003) {
1301         updateShellCmdsTo5dot3();
1302         updatePatternsTo5dot3();
1303     }
1304 
1305     /* Note that we don't care about unreleased file versions.  Anyone
1306        who is running a CVS or alpha version of NEdit is resposnbile
1307        for managing the preferences file themselves.  Otherwise, it
1308        gets impossible to track the number of "in-between" file formats.
1309        We only do auto-upgrading for a real release. */
1310 
1311     if (PrefData.prefFileRead && (fileVer < 5004)) {
1312         migrateColorResources(prefDB, appDB);
1313         updateShellCmdsTo5dot4();
1314         updatePatternsTo5dot4();
1315     }
1316     if (PrefData.prefFileRead && (fileVer < 5005)) {
1317         updateMacroCmdsTo5dot5();
1318     }
1319     if (PrefData.prefFileRead && (fileVer < 5006)) {
1320         fprintf(stderr, "NEdit: Converting .nedit file to 5.6 version.\n"
1321                 "    To keep, use Preferences -> Save Defaults\n");
1322         updateMacroCmdsTo5dot6();
1323         updatePatternsTo5dot6();
1324     }
1325     /* Migrate colors if there's no config file yet */
1326     if (!PrefData.prefFileRead) {
1327         migrateColorResources(prefDB, appDB);
1328     }
1329 
1330     /* Do further parsing on resource types which RestorePreferences does
1331        not understand and reads as strings, to put them in the final form
1332        in which nedit stores and uses.  If the preferences file was
1333        written by an older version of NEdit, update regular expressions in
1334        highlight patterns to quote braces and use & instead of \0 */
1335     translatePrefFormats(requiresConversion, fileVer);
1336 }
1337 
1338 /*
1339 ** Many of of NEdit's preferences are much more complicated than just simple
1340 ** integers or strings.  These are read as strings, but must be parsed and
1341 ** translated into something meaningful.  This routine does the translation,
1342 ** and, in most cases, frees the original string, which is no longer useful.
1343 **
1344 ** In addition this function covers settings that, while simple, require
1345 ** additional steps before they can be published.
1346 **
1347 ** The argument convertOld attempts a conversion from pre 5.1 format .nedit
1348 ** files (which means patterns and macros may contain regular expressions
1349 ** which are of the older syntax where braces were not quoted, and \0 was a
1350 ** legal substitution character).  Macros, so far can not be automatically
1351 ** converted, unfortunately.
1352 */
translatePrefFormats(int convertOld,int fileVer)1353 static void translatePrefFormats(int convertOld, int fileVer)
1354 {
1355     XFontStruct *font;
1356 
1357     /* Parse the strings which represent types which are not decoded by
1358        the standard resource manager routines */
1359 #ifndef VMS
1360     if (TempStringPrefs.shellCmds != NULL) {
1361 	LoadShellCmdsString(TempStringPrefs.shellCmds);
1362 	NEditFree(TempStringPrefs.shellCmds);
1363 	TempStringPrefs.shellCmds = NULL;
1364     }
1365 #endif /* VMS */
1366     if (TempStringPrefs.macroCmds != NULL) {
1367 	LoadMacroCmdsString(TempStringPrefs.macroCmds);
1368     	NEditFree(TempStringPrefs.macroCmds);
1369 	TempStringPrefs.macroCmds = NULL;
1370     }
1371     if (TempStringPrefs.bgMenuCmds != NULL) {
1372 	LoadBGMenuCmdsString(TempStringPrefs.bgMenuCmds);
1373     	NEditFree(TempStringPrefs.bgMenuCmds);
1374 	TempStringPrefs.bgMenuCmds = NULL;
1375     }
1376     if (TempStringPrefs.highlight != NULL) {
1377 	LoadHighlightString(TempStringPrefs.highlight, convertOld);
1378     	NEditFree(TempStringPrefs.highlight);
1379 	TempStringPrefs.highlight = NULL;
1380     }
1381     if (TempStringPrefs.styles != NULL) {
1382 	LoadStylesString(TempStringPrefs.styles);
1383     	NEditFree(TempStringPrefs.styles);
1384 	TempStringPrefs.styles = NULL;
1385     }
1386     if (TempStringPrefs.language != NULL) {
1387 	loadLanguageModesString(TempStringPrefs.language, fileVer);
1388     	NEditFree(TempStringPrefs.language);
1389 	TempStringPrefs.language = NULL;
1390     }
1391     if (TempStringPrefs.smartIndent != NULL) {
1392 	LoadSmartIndentString(TempStringPrefs.smartIndent);
1393     	NEditFree(TempStringPrefs.smartIndent);
1394 	TempStringPrefs.smartIndent = NULL;
1395     }
1396     if (TempStringPrefs.smartIndentCommon != NULL) {
1397 	LoadSmartIndentCommonString(TempStringPrefs.smartIndentCommon);
1398 	NEditFree(TempStringPrefs.smartIndentCommon);
1399 	TempStringPrefs.smartIndentCommon = NULL;
1400     }
1401 
1402     /* translate the font names into fontLists suitable for the text widget */
1403     font = XLoadQueryFont(TheDisplay, PrefData.fontString);
1404     PrefData.fontList = font==NULL ? NULL :
1405 	    XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET);
1406     PrefData.boldFontStruct = XLoadQueryFont(TheDisplay,
1407     	    PrefData.boldFontString);
1408     PrefData.italicFontStruct = XLoadQueryFont(TheDisplay,
1409     	    PrefData.italicFontString);
1410     PrefData.boldItalicFontStruct = XLoadQueryFont(TheDisplay,
1411     	    PrefData.boldItalicFontString);
1412 
1413     /*
1414     **  The default set for the comand shell in PrefDescrip ("DEFAULT") is
1415     **  only a place-holder, the actual default is the user's login shell
1416     **  (or whatever is implemented in getDefaultShell()). We put the login
1417     **  shell's name in PrefData here.
1418     */
1419     if (0 == strcmp(PrefData.shell, "DEFAULT")) {
1420         strncpy(PrefData.shell, getDefaultShell(), MAXPATHLEN);
1421         PrefData.shell[MAXPATHLEN] = '\0';
1422     }
1423 
1424     /* For compatability with older (4.0.3 and before) versions, the autoWrap
1425        and autoIndent resources can accept values of True and False.  Translate
1426        them into acceptable wrap and indent styles */
1427     if (PrefData.wrapStyle == 3) PrefData.wrapStyle = CONTINUOUS_WRAP;
1428     if (PrefData.wrapStyle == 4) PrefData.wrapStyle = NO_WRAP;
1429     if (PrefData.autoIndent == 3) PrefData.autoIndent = AUTO_INDENT;
1430     if (PrefData.autoIndent == 4) PrefData.autoIndent = NO_AUTO_INDENT;
1431 
1432     /* setup language mode dependent info of user menus (to increase
1433        performance when switching between documents of different
1434        language modes) */
1435     SetupUserMenuInfo();
1436 }
1437 
SaveNEditPrefs(Widget parent,int quietly)1438 void SaveNEditPrefs(Widget parent, int quietly)
1439 {
1440     const char* prefFileName = GetRCFileName(NEDIT_RC);
1441     if (prefFileName == NULL)
1442     {
1443         /*  GetRCFileName() might return NULL if an error occurs during
1444             creation of the preference file directory. */
1445         DialogF(DF_WARN, parent, 1, "Error saving Preferences",
1446                 "Unable to save preferences: Cannot determine filename.",
1447                 "OK");
1448         return;
1449     }
1450 
1451     if (!quietly) {
1452         if (DialogF(DF_INF, parent, 2, "Save Preferences",
1453                 ImportedFile == NULL ?
1454                 "Default preferences will be saved in the file:\n"
1455                 "%s\n"
1456                 "NEdit automatically loads this file\n"
1457                 "each time it is started." :
1458                 "Default preferences will be saved in the file:\n"
1459                 "%s\n"
1460                 "SAVING WILL INCORPORATE SETTINGS\n"
1461                 "FROM FILE: %s", "OK", "Cancel",
1462                 prefFileName, ImportedFile) == 2) {
1463             return;
1464         }
1465     }
1466 
1467     /*  Write the more dynamic settings into TempStringPrefs.
1468         These locations are set in PrefDescrip, so this is where
1469         SavePreferences() will look for them.  */
1470 #ifndef VMS
1471     TempStringPrefs.shellCmds = WriteShellCmdsString();
1472 #endif /* VMS */
1473     TempStringPrefs.macroCmds = WriteMacroCmdsString();
1474     TempStringPrefs.bgMenuCmds = WriteBGMenuCmdsString();
1475     TempStringPrefs.highlight = WriteHighlightString();
1476     TempStringPrefs.language = writeLanguageModesString();
1477     TempStringPrefs.styles = WriteStylesString();
1478     TempStringPrefs.smartIndent = WriteSmartIndentString();
1479     TempStringPrefs.smartIndentCommon = WriteSmartIndentCommonString();
1480     strcpy(PrefData.fileVersion, PREF_FILE_VERSION);
1481 
1482     if (!SavePreferences(XtDisplay(parent), prefFileName, HeaderText,
1483             PrefDescrip, XtNumber(PrefDescrip)))
1484     {
1485         DialogF(DF_WARN, parent, 1, "Save Preferences",
1486                 "Unable to save preferences in %s", "OK", prefFileName);
1487     }
1488 
1489 #ifndef VMS
1490     NEditFree(TempStringPrefs.shellCmds);
1491 #endif /* VMS */
1492     NEditFree(TempStringPrefs.macroCmds);
1493     NEditFree(TempStringPrefs.bgMenuCmds);
1494     NEditFree(TempStringPrefs.highlight);
1495     NEditFree(TempStringPrefs.language);
1496     NEditFree(TempStringPrefs.styles);
1497     NEditFree(TempStringPrefs.smartIndent);
1498     NEditFree(TempStringPrefs.smartIndentCommon);
1499 
1500     PrefsHaveChanged = False;
1501 }
1502 
1503 /*
1504 ** Load an additional preferences file on top of the existing preferences
1505 ** derived from defaults, the .nedit file, and X resources.
1506 */
ImportPrefFile(const char * filename,int convertOld)1507 void ImportPrefFile(const char *filename, int convertOld)
1508 {
1509     XrmDatabase db;
1510     char *fileString;
1511 
1512     fileString = ReadAnyTextFile(filename, False);
1513     if (fileString != NULL){
1514         db = XrmGetStringDatabase(fileString);
1515         NEditFree(fileString);
1516         OverlayPreferences(db, APP_NAME, APP_CLASS, PrefDescrip,
1517         XtNumber(PrefDescrip));
1518         translatePrefFormats(convertOld, -1);
1519         ImportedFile = NEditStrdup(filename);
1520     } else
1521     {
1522         fprintf(stderr, "Could not read additional preferences file: %s\n",
1523                 filename);
1524     }
1525 }
1526 
SetPrefOpenInTab(int state)1527 void SetPrefOpenInTab(int state)
1528 {
1529     WindowInfo *w = WindowList;
1530     setIntPref(&PrefData.openInTab, state);
1531     for(; w != NULL; w = w->next)
1532         UpdateNewOppositeMenu(w, state);
1533 }
1534 
GetPrefOpenInTab(void)1535 int GetPrefOpenInTab(void)
1536 {
1537     return PrefData.openInTab;
1538 }
1539 
SetPrefWrap(WrapStyle state)1540 void SetPrefWrap(WrapStyle state)
1541 {
1542     setIntPref(&PrefData.wrapStyle, (int)state);
1543 }
1544 
GetPrefWrap(int langMode)1545 WrapStyle GetPrefWrap(int langMode)
1546 {
1547     if (langMode == PLAIN_LANGUAGE_MODE ||
1548 	    LanguageModes[langMode]->wrapStyle == DEFAULT_WRAP)
1549     	return (WrapStyle)(PrefData.wrapStyle);
1550     return LanguageModes[langMode]->wrapStyle;
1551 }
1552 
SetPrefWrapMargin(int margin)1553 void SetPrefWrapMargin(int margin)
1554 {
1555     setIntPref(&PrefData.wrapMargin, margin);
1556 }
1557 
GetPrefWrapMargin(void)1558 int GetPrefWrapMargin(void)
1559 {
1560     return PrefData.wrapMargin;
1561 }
1562 
SetPrefSearch(int searchType)1563 void SetPrefSearch(int searchType)
1564 {
1565     setIntPref(&PrefData.searchMethod, searchType);
1566 }
1567 
GetPrefSearch(void)1568 int GetPrefSearch(void)
1569 {
1570     return PrefData.searchMethod;
1571 }
1572 
1573 #ifdef REPLACE_SCOPE
SetPrefReplaceDefScope(int scope)1574 void SetPrefReplaceDefScope(int scope)
1575 {
1576     setIntPref(&PrefData.replaceDefScope, scope);
1577 }
1578 
GetPrefReplaceDefScope(void)1579 int GetPrefReplaceDefScope(void)
1580 {
1581     return PrefData.replaceDefScope;
1582 }
1583 #endif
1584 
SetPrefAutoIndent(IndentStyle state)1585 void SetPrefAutoIndent(IndentStyle state)
1586 {
1587     setIntPref(&PrefData.autoIndent, (int)state);
1588 }
1589 
GetPrefAutoIndent(int langMode)1590 IndentStyle GetPrefAutoIndent(int langMode)
1591 {
1592     if (langMode == PLAIN_LANGUAGE_MODE ||
1593 	    LanguageModes[langMode]->indentStyle == DEFAULT_INDENT)
1594     	return (IndentStyle)(PrefData.autoIndent);
1595     return LanguageModes[langMode]->indentStyle;
1596 }
1597 
SetPrefAutoSave(int state)1598 void SetPrefAutoSave(int state)
1599 {
1600     setIntPref(&PrefData.autoSave, state);
1601 }
1602 
GetPrefAutoSave(void)1603 int GetPrefAutoSave(void)
1604 {
1605     return PrefData.autoSave;
1606 }
1607 
SetPrefSaveOldVersion(int state)1608 void SetPrefSaveOldVersion(int state)
1609 {
1610     setIntPref(&PrefData.saveOldVersion, state);
1611 }
1612 
GetPrefSaveOldVersion(void)1613 int GetPrefSaveOldVersion(void)
1614 {
1615     return PrefData.saveOldVersion;
1616 }
1617 
SetPrefSearchDlogs(int state)1618 void SetPrefSearchDlogs(int state)
1619 {
1620     setIntPref(&PrefData.searchDlogs, state);
1621 }
1622 
GetPrefSearchDlogs(void)1623 int GetPrefSearchDlogs(void)
1624 {
1625     return PrefData.searchDlogs;
1626 }
1627 
SetPrefBeepOnSearchWrap(int state)1628 void SetPrefBeepOnSearchWrap(int state)
1629 {
1630     setIntPref(&PrefData.searchWrapBeep, state);
1631 }
1632 
GetPrefBeepOnSearchWrap(void)1633 int GetPrefBeepOnSearchWrap(void)
1634 {
1635     return PrefData.searchWrapBeep;
1636 }
1637 
SetPrefKeepSearchDlogs(int state)1638 void SetPrefKeepSearchDlogs(int state)
1639 {
1640     setIntPref(&PrefData.keepSearchDlogs, state);
1641 }
1642 
GetPrefKeepSearchDlogs(void)1643 int GetPrefKeepSearchDlogs(void)
1644 {
1645     return PrefData.keepSearchDlogs;
1646 }
1647 
SetPrefSearchWraps(int state)1648 void SetPrefSearchWraps(int state)
1649 {
1650     setIntPref(&PrefData.searchWraps, state);
1651 }
1652 
GetPrefStickyCaseSenseBtn(void)1653 int GetPrefStickyCaseSenseBtn(void)
1654 {
1655     return PrefData.stickyCaseSenseBtn;
1656 }
1657 
GetPrefSearchWraps(void)1658 int GetPrefSearchWraps(void)
1659 {
1660     return PrefData.searchWraps;
1661 }
1662 
SetPrefStatsLine(int state)1663 void SetPrefStatsLine(int state)
1664 {
1665     setIntPref(&PrefData.statsLine, state);
1666 }
1667 
GetPrefStatsLine(void)1668 int GetPrefStatsLine(void)
1669 {
1670     return PrefData.statsLine;
1671 }
1672 
SetPrefISearchLine(int state)1673 void SetPrefISearchLine(int state)
1674 {
1675     setIntPref(&PrefData.iSearchLine, state);
1676 }
1677 
GetPrefISearchLine(void)1678 int GetPrefISearchLine(void)
1679 {
1680     return PrefData.iSearchLine;
1681 }
1682 
SetPrefSortTabs(int state)1683 void SetPrefSortTabs(int state)
1684 {
1685     setIntPref(&PrefData.sortTabs, state);
1686 }
1687 
GetPrefSortTabs(void)1688 int GetPrefSortTabs(void)
1689 {
1690     return PrefData.sortTabs;
1691 }
1692 
SetPrefTabBar(int state)1693 void SetPrefTabBar(int state)
1694 {
1695     setIntPref(&PrefData.tabBar, state);
1696 }
1697 
GetPrefTabBar(void)1698 int GetPrefTabBar(void)
1699 {
1700     return PrefData.tabBar;
1701 }
1702 
SetPrefTabBarHideOne(int state)1703 void SetPrefTabBarHideOne(int state)
1704 {
1705     setIntPref(&PrefData.tabBarHideOne, state);
1706 }
1707 
GetPrefTabBarHideOne(void)1708 int GetPrefTabBarHideOne(void)
1709 {
1710     return PrefData.tabBarHideOne;
1711 }
1712 
SetPrefGlobalTabNavigate(int state)1713 void SetPrefGlobalTabNavigate(int state)
1714 {
1715     setIntPref(&PrefData.globalTabNavigate, state);
1716 }
1717 
GetPrefGlobalTabNavigate(void)1718 int GetPrefGlobalTabNavigate(void)
1719 {
1720     return PrefData.globalTabNavigate;
1721 }
1722 
SetPrefToolTips(int state)1723 void SetPrefToolTips(int state)
1724 {
1725     setIntPref(&PrefData.toolTips, state);
1726 }
1727 
GetPrefToolTips(void)1728 int GetPrefToolTips(void)
1729 {
1730     return PrefData.toolTips;
1731 }
1732 
SetPrefLineNums(int state)1733 void SetPrefLineNums(int state)
1734 {
1735     setIntPref(&PrefData.lineNums, state);
1736 }
1737 
GetPrefLineNums(void)1738 int GetPrefLineNums(void)
1739 {
1740     return PrefData.lineNums;
1741 }
1742 
SetPrefShowPathInWindowsMenu(int state)1743 void SetPrefShowPathInWindowsMenu(int state)
1744 {
1745     setIntPref(&PrefData.pathInWindowsMenu, state);
1746 }
1747 
GetPrefShowPathInWindowsMenu(void)1748 int GetPrefShowPathInWindowsMenu(void)
1749 {
1750     return PrefData.pathInWindowsMenu;
1751 }
1752 
SetPrefWarnFileMods(int state)1753 void SetPrefWarnFileMods(int state)
1754 {
1755     setIntPref(&PrefData.warnFileMods, state);
1756 }
1757 
GetPrefWarnFileMods(void)1758 int GetPrefWarnFileMods(void)
1759 {
1760     return PrefData.warnFileMods;
1761 }
1762 
SetPrefWarnRealFileMods(int state)1763 void SetPrefWarnRealFileMods(int state)
1764 {
1765     setIntPref(&PrefData.warnRealFileMods, state);
1766 }
1767 
GetPrefWarnRealFileMods(void)1768 int GetPrefWarnRealFileMods(void)
1769 {
1770     return PrefData.warnRealFileMods;
1771 }
1772 
SetPrefWarnExit(int state)1773 void SetPrefWarnExit(int state)
1774 {
1775     setIntPref(&PrefData.warnExit, state);
1776 }
1777 
GetPrefWarnExit(void)1778 int GetPrefWarnExit(void)
1779 {
1780     return PrefData.warnExit;
1781 }
1782 
SetPrefv(int state)1783 void SetPrefv(int state)
1784 {
1785     setIntPref(&PrefData.findReplaceUsesSelection, state);
1786 }
1787 
GetPrefFindReplaceUsesSelection(void)1788 int GetPrefFindReplaceUsesSelection(void)
1789 {
1790     return PrefData.findReplaceUsesSelection;
1791 }
1792 
GetPrefMapDelete(void)1793 int GetPrefMapDelete(void)
1794 {
1795     return PrefData.mapDelete;
1796 }
1797 
GetPrefStdOpenDialog(void)1798 int GetPrefStdOpenDialog(void)
1799 {
1800     return PrefData.stdOpenDialog;
1801 }
1802 
SetPrefRows(int nRows)1803 void SetPrefRows(int nRows)
1804 {
1805     setIntPref(&PrefData.textRows, nRows);
1806 }
1807 
GetPrefRows(void)1808 int GetPrefRows(void)
1809 {
1810     return PrefData.textRows;
1811 }
1812 
SetPrefCols(int nCols)1813 void SetPrefCols(int nCols)
1814 {
1815    setIntPref(&PrefData.textCols, nCols);
1816 }
1817 
GetPrefCols(void)1818 int GetPrefCols(void)
1819 {
1820     return PrefData.textCols;
1821 }
1822 
SetPrefTabDist(int tabDist)1823 void SetPrefTabDist(int tabDist)
1824 {
1825     setIntPref(&PrefData.tabDist, tabDist);
1826 }
1827 
GetPrefTabDist(int langMode)1828 int GetPrefTabDist(int langMode)
1829 {
1830     int tabDist;
1831     if (langMode == PLAIN_LANGUAGE_MODE ||
1832 	    LanguageModes[langMode]->tabDist == DEFAULT_TAB_DIST) {
1833 	tabDist = PrefData.tabDist;
1834     } else {
1835 	tabDist = LanguageModes[langMode]->tabDist;
1836     }
1837     /* Make sure that the tab distance is in range (garbage may have
1838        been entered via the command line or the X resources, causing
1839        errors later on, like division by zero). */
1840     if (tabDist <= 0) return 1;
1841     if (tabDist > MAX_EXP_CHAR_LEN) return MAX_EXP_CHAR_LEN;
1842     return tabDist;
1843 }
1844 
SetPrefEmTabDist(int tabDist)1845 void SetPrefEmTabDist(int tabDist)
1846 {
1847     setIntPref(&PrefData.emTabDist, tabDist);
1848 }
1849 
GetPrefEmTabDist(int langMode)1850 int GetPrefEmTabDist(int langMode)
1851 {
1852     if (langMode == PLAIN_LANGUAGE_MODE ||
1853 	    LanguageModes[langMode]->emTabDist == DEFAULT_EM_TAB_DIST)
1854 	return PrefData.emTabDist;
1855     return LanguageModes[langMode]->emTabDist;
1856 }
1857 
SetPrefInsertTabs(int state)1858 void SetPrefInsertTabs(int state)
1859 {
1860     setIntPref(&PrefData.insertTabs, state);
1861 }
1862 
GetPrefInsertTabs(void)1863 int GetPrefInsertTabs(void)
1864 {
1865     return PrefData.insertTabs;
1866 }
1867 
SetPrefShowMatching(ShowMatchingStyle state)1868 void SetPrefShowMatching(ShowMatchingStyle state)
1869 {
1870     setIntPref(&PrefData.showMatchingStyle, (int)state);
1871 }
1872 
GetPrefShowMatching(void)1873 ShowMatchingStyle GetPrefShowMatching(void)
1874 {
1875     /*
1876      * For backwards compatibility with pre-5.2 versions, the boolean
1877      * False/True matching behavior is converted to NO_FLASH/FLASH_DELIMIT.
1878      */
1879     if (PrefData.showMatchingStyle >= N_SHOW_MATCHING_STYLES)
1880 	PrefData.showMatchingStyle -= N_SHOW_MATCHING_STYLES;
1881     return (ShowMatchingStyle)(PrefData.showMatchingStyle);
1882 }
1883 
SetPrefMatchSyntaxBased(int state)1884 void SetPrefMatchSyntaxBased(int state)
1885 {
1886     setIntPref(&PrefData.matchSyntaxBased, state);
1887 }
1888 
GetPrefMatchSyntaxBased(void)1889 int GetPrefMatchSyntaxBased(void)
1890 {
1891     return PrefData.matchSyntaxBased;
1892 }
1893 
SetPrefHighlightSyntax(Boolean state)1894 void SetPrefHighlightSyntax(Boolean state)
1895 {
1896     setIntPref(&PrefData.highlightSyntax, state);
1897 }
1898 
GetPrefHighlightSyntax(void)1899 Boolean GetPrefHighlightSyntax(void)
1900 {
1901     return PrefData.highlightSyntax;
1902 }
1903 
SetPrefBacklightChars(int state)1904 void SetPrefBacklightChars(int state)
1905 {
1906     setIntPref(&PrefData.backlightChars, state);
1907 }
1908 
GetPrefBacklightChars(void)1909 int GetPrefBacklightChars(void)
1910 {
1911     return PrefData.backlightChars;
1912 }
1913 
SetPrefBacklightCharTypes(char * types)1914 void SetPrefBacklightCharTypes(char *types)
1915 {
1916     setStringAllocPref(&PrefData.backlightCharTypes, types);
1917 }
1918 
GetPrefBacklightCharTypes(void)1919 char *GetPrefBacklightCharTypes(void)
1920 {
1921     return PrefData.backlightCharTypes;
1922 }
1923 
SetPrefRepositionDialogs(int state)1924 void SetPrefRepositionDialogs(int state)
1925 {
1926     setIntPref(&PrefData.repositionDialogs, state);
1927 }
1928 
GetPrefRepositionDialogs(void)1929 int GetPrefRepositionDialogs(void)
1930 {
1931     return PrefData.repositionDialogs;
1932 }
1933 
SetPrefAutoScroll(int state)1934 void SetPrefAutoScroll(int state)
1935 {
1936     WindowInfo *w = WindowList;
1937     int margin = state ? PrefData.autoScrollVPadding : 0;
1938 
1939     setIntPref(&PrefData.autoScroll, state);
1940     for(w = WindowList; w != NULL; w = w->next)
1941         SetAutoScroll(w, margin);
1942 }
1943 
GetPrefAutoScroll(void)1944 int GetPrefAutoScroll(void)
1945 {
1946     return PrefData.autoScroll;
1947 }
1948 
GetVerticalAutoScroll(void)1949 int GetVerticalAutoScroll(void)
1950 {
1951     return PrefData.autoScroll ? PrefData.autoScrollVPadding : 0;
1952 }
1953 
SetPrefAppendLF(int state)1954 void SetPrefAppendLF(int state)
1955 {
1956     setIntPref(&PrefData.appendLF, state);
1957 }
1958 
GetPrefAppendLF(void)1959 int GetPrefAppendLF(void)
1960 {
1961     return PrefData.appendLF;
1962 }
1963 
SetPrefSortOpenPrevMenu(int state)1964 void SetPrefSortOpenPrevMenu(int state)
1965 {
1966     setIntPref(&PrefData.sortOpenPrevMenu, state);
1967 }
1968 
GetPrefSortOpenPrevMenu(void)1969 int GetPrefSortOpenPrevMenu(void)
1970 {
1971     return PrefData.sortOpenPrevMenu;
1972 }
1973 
GetPrefTagFile(void)1974 char *GetPrefTagFile(void)
1975 {
1976     return PrefData.tagFile;
1977 }
1978 
SetPrefSmartTags(int state)1979 void SetPrefSmartTags(int state)
1980 {
1981     setIntPref(&PrefData.smartTags, state);
1982 }
1983 
GetPrefSmartTags(void)1984 int GetPrefSmartTags(void)
1985 {
1986     return PrefData.smartTags;
1987 }
1988 
GetPrefAlwaysCheckRelTagsSpecs(void)1989 int GetPrefAlwaysCheckRelTagsSpecs(void)
1990 {
1991     return PrefData.alwaysCheckRelativeTagsSpecs;
1992 }
1993 
GetPrefDelimiters(void)1994 char *GetPrefDelimiters(void)
1995 {
1996     return PrefData.delimiters;
1997 }
1998 
GetPrefColorName(int index)1999 char *GetPrefColorName(int index)
2000 {
2001     return PrefData.colorNames[index];
2002 }
2003 
SetPrefColorName(int index,const char * name)2004 void SetPrefColorName(int index, const char *name)
2005 {
2006     setStringPref(PrefData.colorNames[index], name);
2007 }
2008 
2009 /*
2010 ** Set the font preferences using the font name (the fontList is generated
2011 ** in this call).  Note that this leaks memory and server resources each
2012 ** time the default font is re-set.  See note on SetFontByName in window.c
2013 ** for more information.
2014 */
SetPrefFont(char * fontName)2015 void SetPrefFont(char *fontName)
2016 {
2017     XFontStruct *font;
2018 
2019     setStringPref(PrefData.fontString, fontName);
2020     font = XLoadQueryFont(TheDisplay, fontName);
2021     PrefData.fontList = font==NULL ? NULL :
2022 	    XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET);
2023 }
2024 
SetPrefBoldFont(char * fontName)2025 void SetPrefBoldFont(char *fontName)
2026 {
2027     setStringPref(PrefData.boldFontString, fontName);
2028     PrefData.boldFontStruct = XLoadQueryFont(TheDisplay, fontName);
2029 }
2030 
SetPrefItalicFont(char * fontName)2031 void SetPrefItalicFont(char *fontName)
2032 {
2033     setStringPref(PrefData.italicFontString, fontName);
2034     PrefData.italicFontStruct = XLoadQueryFont(TheDisplay, fontName);
2035 }
SetPrefBoldItalicFont(char * fontName)2036 void SetPrefBoldItalicFont(char *fontName)
2037 {
2038     setStringPref(PrefData.boldItalicFontString, fontName);
2039     PrefData.boldItalicFontStruct = XLoadQueryFont(TheDisplay, fontName);
2040 }
2041 
GetPrefFontName(void)2042 char *GetPrefFontName(void)
2043 {
2044     return PrefData.fontString;
2045 }
2046 
GetPrefBoldFontName(void)2047 char *GetPrefBoldFontName(void)
2048 {
2049     return PrefData.boldFontString;
2050 }
2051 
GetPrefItalicFontName(void)2052 char *GetPrefItalicFontName(void)
2053 {
2054     return PrefData.italicFontString;
2055 }
2056 
GetPrefBoldItalicFontName(void)2057 char *GetPrefBoldItalicFontName(void)
2058 {
2059     return PrefData.boldItalicFontString;
2060 }
2061 
GetPrefFontList(void)2062 XmFontList GetPrefFontList(void)
2063 {
2064     return PrefData.fontList;
2065 }
2066 
GetPrefBoldFont(void)2067 XFontStruct *GetPrefBoldFont(void)
2068 {
2069     return PrefData.boldFontStruct;
2070 }
2071 
GetPrefItalicFont(void)2072 XFontStruct *GetPrefItalicFont(void)
2073 {
2074     return PrefData.italicFontStruct;
2075 }
2076 
GetPrefBoldItalicFont(void)2077 XFontStruct *GetPrefBoldItalicFont(void)
2078 {
2079     return PrefData.boldItalicFontStruct;
2080 }
2081 
GetPrefHelpFontName(int index)2082 char *GetPrefHelpFontName(int index)
2083 {
2084     return PrefData.helpFontNames[index];
2085 }
2086 
GetPrefHelpLinkColor(void)2087 char *GetPrefHelpLinkColor(void)
2088 {
2089     return PrefData.helpLinkColor;
2090 }
2091 
GetPrefTooltipBgColor(void)2092 char *GetPrefTooltipBgColor(void)
2093 {
2094     return PrefData.tooltipBgColor;
2095 }
2096 
SetPrefShell(const char * shell)2097 void SetPrefShell(const char *shell)
2098 {
2099     setStringPref(PrefData.shell, shell);
2100 }
2101 
GetPrefShell(void)2102 const char* GetPrefShell(void)
2103 {
2104     return PrefData.shell;
2105 }
2106 
GetPrefGeometry(void)2107 char *GetPrefGeometry(void)
2108 {
2109     return PrefData.geometry;
2110 }
2111 
GetPrefServerName(void)2112 char *GetPrefServerName(void)
2113 {
2114     return PrefData.serverName;
2115 }
2116 
GetPrefBGMenuBtn(void)2117 char *GetPrefBGMenuBtn(void)
2118 {
2119     return PrefData.bgMenuBtn;
2120 }
2121 
GetPrefMaxPrevOpenFiles(void)2122 int GetPrefMaxPrevOpenFiles(void)
2123 {
2124     return PrefData.maxPrevOpenFiles;
2125 }
2126 
GetPrefTypingHidesPointer(void)2127 int GetPrefTypingHidesPointer(void)
2128 {
2129     return(PrefData.typingHidesPointer);
2130 }
2131 
2132 #ifdef SGI_CUSTOM
SetPrefShortMenus(int state)2133 void SetPrefShortMenus(int state)
2134 {
2135     setIntPref(&PrefData.shortMenus, state);
2136 }
2137 
GetPrefShortMenus(void)2138 int GetPrefShortMenus(void)
2139 {
2140     return PrefData.shortMenus;
2141 }
2142 #endif
2143 
SetPrefTitleFormat(const char * format)2144 void SetPrefTitleFormat(const char* format)
2145 {
2146     const WindowInfo* window;
2147 
2148     setStringPref(PrefData.titleFormat, format);
2149 
2150     /* update all windows */
2151     for (window=WindowList; window!=NULL; window=window->next) {
2152         UpdateWindowTitle(window);
2153     }
2154 }
GetPrefTitleFormat(void)2155 const char* GetPrefTitleFormat(void)
2156 {
2157     return PrefData.titleFormat;
2158 }
2159 
GetPrefUndoModifiesSelection(void)2160 Boolean GetPrefUndoModifiesSelection(void)
2161 {
2162     return (Boolean)PrefData.undoModifiesSelection;
2163 }
2164 
GetPrefFocusOnRaise(void)2165 Boolean GetPrefFocusOnRaise(void)
2166 {
2167     return (Boolean)PrefData.focusOnRaise;
2168 }
2169 
GetPrefForceOSConversion(void)2170 Boolean GetPrefForceOSConversion(void)
2171 {
2172     return (Boolean) PrefData.forceOSConversion;
2173 }
2174 
GetPrefHonorSymlinks(void)2175 Boolean GetPrefHonorSymlinks(void)
2176 {
2177     return PrefData.honorSymlinks;
2178 }
2179 
GetPrefOverrideVirtKeyBindings(void)2180 int GetPrefOverrideVirtKeyBindings(void)
2181 {
2182     return PrefData.virtKeyOverride;
2183 }
2184 
GetPrefTruncSubstitution(void)2185 int GetPrefTruncSubstitution(void)
2186 {
2187     return PrefData.truncSubstitution;
2188 }
2189 
2190 /*
2191 ** If preferences don't get saved, ask the user on exit whether to save
2192 */
MarkPrefsChanged(void)2193 void MarkPrefsChanged(void)
2194 {
2195     PrefsHaveChanged = True;
2196 }
2197 
2198 /*
2199 ** Check if preferences have changed, and if so, ask the user if he wants
2200 ** to re-save.  Returns False if user requests cancelation of Exit (or whatever
2201 ** operation triggered this call to be made).
2202 */
CheckPrefsChangesSaved(Widget dialogParent)2203 int CheckPrefsChangesSaved(Widget dialogParent)
2204 {
2205     int resp;
2206 
2207     if (!PrefsHaveChanged)
2208         return True;
2209 
2210     resp = DialogF(DF_WARN, dialogParent, 3, "Default Preferences",
2211             ImportedFile == NULL ?
2212             "Default Preferences have changed.\n"
2213             "Save changes to NEdit preference file?" :
2214             "Default Preferences have changed.  SAVING \n"
2215             "CHANGES WILL INCORPORATE ADDITIONAL\nSETTINGS FROM FILE: %s",
2216             "Save", "Don't Save", "Cancel", ImportedFile);
2217     if (resp == 2)
2218         return True;
2219     if (resp == 3)
2220         return False;
2221 
2222     SaveNEditPrefs(dialogParent, True);
2223     return True;
2224 }
2225 
2226 /*
2227 ** set *prefDataField to newValue, but first check if they're different
2228 ** and update PrefsHaveChanged if a preference setting has now changed.
2229 */
setIntPref(int * prefDataField,int newValue)2230 static void setIntPref(int *prefDataField, int newValue)
2231 {
2232     if (newValue != *prefDataField)
2233 	PrefsHaveChanged = True;
2234     *prefDataField = newValue;
2235 }
2236 
setStringPref(char * prefDataField,const char * newValue)2237 static void setStringPref(char *prefDataField, const char *newValue)
2238 {
2239     if (strcmp(prefDataField, newValue))
2240 	PrefsHaveChanged = True;
2241     strcpy(prefDataField, newValue);
2242 }
2243 
setStringAllocPref(char ** pprefDataField,char * newValue)2244 static void setStringAllocPref(char **pprefDataField, char *newValue)
2245 {
2246     char *p_newField;
2247 
2248     /* treat empty strings as nulls */
2249     if (newValue && *newValue == '\0')
2250       newValue = NULL;
2251     if (*pprefDataField && **pprefDataField == '\0')
2252       *pprefDataField = NULL;         /* assume statically alloc'ed "" */
2253 
2254     /* check changes */
2255     if (!*pprefDataField && !newValue)
2256       return;
2257     else if (!*pprefDataField && newValue)
2258       PrefsHaveChanged = True;
2259     else if (*pprefDataField && !newValue)
2260       PrefsHaveChanged = True;
2261     else if (strcmp(*pprefDataField, newValue))
2262       PrefsHaveChanged = True;
2263 
2264     /* get rid of old preference */
2265     NEditFree(*pprefDataField);
2266 
2267     /* store new preference */
2268     if (newValue) {
2269       p_newField = NEditStrdup(newValue);
2270     }
2271     *pprefDataField = newValue;
2272 }
2273 
2274 /*
2275 ** Set the language mode for the window, update the menu and trigger language
2276 ** mode specific actions (turn on/off highlighting).  If forceNewDefaults is
2277 ** true, re-establish default settings for language-specific preferences
2278 ** regardless of whether they were previously set by the user.
2279 */
SetLanguageMode(WindowInfo * window,int mode,int forceNewDefaults)2280 void SetLanguageMode(WindowInfo *window, int mode, int forceNewDefaults)
2281 {
2282     Widget menu;
2283     WidgetList items;
2284     int n;
2285     Cardinal nItems;
2286     void *userData;
2287 
2288     /* Do mode-specific actions */
2289     reapplyLanguageMode(window, mode, forceNewDefaults);
2290 
2291     /* Select the correct language mode in the sub-menu */
2292     if (IsTopDocument(window)) {
2293 	XtVaGetValues(window->langModeCascade, XmNsubMenuId, &menu, NULL);
2294 	XtVaGetValues(menu, XmNchildren, &items, XmNnumChildren, &nItems, NULL);
2295 	for (n=0; n<(int)nItems; n++) {
2296     	    XtVaGetValues(items[n], XmNuserData, &userData, NULL);
2297     	    XmToggleButtonSetState(items[n], (int)(intptr_t)userData == mode, False);
2298 	}
2299     }
2300 }
2301 
2302 /*
2303 ** Lookup a language mode by name, returning the index of the language
2304 ** mode or PLAIN_LANGUAGE_MODE if the name is not found
2305 */
FindLanguageMode(const char * languageName)2306 int FindLanguageMode(const char *languageName)
2307 {
2308     int i;
2309 
2310     /* Compare each language mode to the one we were presented */
2311     for (i=0; i<NLanguageModes; i++)
2312 	if (!strcmp(languageName, LanguageModes[i]->name))
2313 	    return i;
2314 
2315     return PLAIN_LANGUAGE_MODE;
2316 }
2317 
2318 
2319 /*
2320 ** Apply language mode matching criteria and set window->languageMode to
2321 ** the appropriate mode for the current file, trigger language mode
2322 ** specific actions (turn on/off highlighting), and update the language
2323 ** mode menu item.  If forceNewDefaults is true, re-establish default
2324 ** settings for language-specific preferences regardless of whether
2325 ** they were previously set by the user.
2326 */
DetermineLanguageMode(WindowInfo * window,int forceNewDefaults)2327 void DetermineLanguageMode(WindowInfo *window, int forceNewDefaults)
2328 {
2329     SetLanguageMode(window, matchLanguageMode(window), forceNewDefaults);
2330 }
2331 
2332 /*
2333 ** Return the name of the current language mode set in "window", or NULL
2334 ** if the current mode is "Plain".
2335 */
LanguageModeName(int mode)2336 char *LanguageModeName(int mode)
2337 {
2338     if (mode == PLAIN_LANGUAGE_MODE)
2339     	return NULL;
2340     else
2341     	return LanguageModes[mode]->name;
2342 }
2343 
2344 /*
2345 ** Get the set of word delimiters for the language mode set in the current
2346 ** window.  Returns NULL when no language mode is set (it would be easy to
2347 ** return the default delimiter set when the current language mode is "Plain",
2348 ** or the mode doesn't have its own delimiters, but this is usually used
2349 ** to supply delimiters for RE searching, and ExecRE can skip compiling a
2350 ** delimiter table when delimiters is NULL).
2351 */
GetWindowDelimiters(const WindowInfo * window)2352 char *GetWindowDelimiters(const WindowInfo *window)
2353 {
2354     if (window->languageMode == PLAIN_LANGUAGE_MODE)
2355     	return NULL;
2356     else
2357     	return LanguageModes[window->languageMode]->delimiters;
2358 }
2359 
2360 /*
2361 ** Put up a dialog for selecting a custom initial window size
2362 */
RowColumnPrefDialog(Widget parent)2363 void RowColumnPrefDialog(Widget parent)
2364 {
2365     Widget form, selBox, topLabel;
2366     Arg selBoxArgs[2];
2367     XmString s1;
2368 
2369     XtSetArg(selBoxArgs[0], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
2370     XtSetArg(selBoxArgs[1], XmNautoUnmanage, False);
2371     selBox = CreatePromptDialog(parent, "customSize", selBoxArgs, 2);
2372     XtAddCallback(selBox, XmNokCallback, (XtCallbackProc)sizeOKCB, NULL);
2373     XtAddCallback(selBox, XmNcancelCallback, (XtCallbackProc)sizeCancelCB,NULL);
2374     XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_TEXT));
2375     XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_SELECTION_LABEL));
2376     XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_HELP_BUTTON));
2377     XtVaSetValues(XtParent(selBox), XmNtitle, "Initial Window Size", NULL);
2378 
2379     form = XtVaCreateManagedWidget("form", xmFormWidgetClass, selBox, NULL);
2380 
2381     topLabel = XtVaCreateManagedWidget("topLabel", xmLabelGadgetClass, form,
2382     	    XmNlabelString, s1=MKSTRING(
2383     	       "Enter desired size in rows\nand columns of characters:"), NULL);
2384     XmStringFree(s1);
2385 
2386     RowText = XtVaCreateManagedWidget("rows", xmTextWidgetClass, form,
2387     	    XmNcolumns, 3,
2388     	    XmNtopAttachment, XmATTACH_WIDGET,
2389     	    XmNleftAttachment, XmATTACH_POSITION,
2390     	    XmNrightAttachment, XmATTACH_POSITION,
2391     	    XmNtopWidget, topLabel,
2392     	    XmNleftPosition, 5,
2393     	    XmNrightPosition, 45, NULL);
2394     RemapDeleteKey(RowText);
2395 
2396     XtVaCreateManagedWidget("xLabel", xmLabelGadgetClass, form,
2397     	    XmNlabelString, s1=MKSTRING("x"),
2398     	    XmNtopAttachment, XmATTACH_WIDGET,
2399     	    XmNleftAttachment, XmATTACH_POSITION,
2400     	    XmNrightAttachment, XmATTACH_POSITION,
2401     	    XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
2402     	    XmNtopWidget, topLabel,
2403     	    XmNbottomWidget, RowText,
2404     	    XmNleftPosition, 45,
2405     	    XmNrightPosition, 55, NULL);
2406     XmStringFree(s1);
2407 
2408     ColText = XtVaCreateManagedWidget("cols", xmTextWidgetClass, form,
2409     	    XmNcolumns, 3,
2410     	    XmNtopAttachment, XmATTACH_WIDGET,
2411     	    XmNleftAttachment, XmATTACH_POSITION,
2412     	    XmNrightAttachment, XmATTACH_POSITION,
2413     	    XmNtopWidget, topLabel,
2414     	    XmNleftPosition, 55,
2415     	    XmNrightPosition, 95, NULL);
2416     RemapDeleteKey(ColText);
2417 
2418     /* put up dialog and wait for user to press ok or cancel */
2419     DoneWithSizeDialog = False;
2420     ManageDialogCenteredOnPointer(selBox);
2421     while (!DoneWithSizeDialog)
2422     {
2423        	XEvent event;
2424        	XtAppNextEvent(XtWidgetToApplicationContext(parent), &event);
2425        	ServerDispatchEvent(&event);
2426     }
2427 
2428     XtDestroyWidget(selBox);
2429 }
2430 
sizeOKCB(Widget w,XtPointer clientData,XtPointer callData)2431 static void sizeOKCB(Widget w, XtPointer clientData, XtPointer callData)
2432 {
2433     int rowValue, colValue, stat;
2434 
2435     /* get the values that the user entered and make sure they're ok */
2436     stat = GetIntTextWarn(RowText, &rowValue, "number of rows", True);
2437     if (stat != TEXT_READ_OK)
2438     	return;
2439     stat = GetIntTextWarn(ColText, &colValue, "number of columns", True);
2440     if (stat != TEXT_READ_OK)
2441     	return;
2442 
2443     /* set the corresponding preferences and dismiss the dialog */
2444     SetPrefRows(rowValue);
2445     SetPrefCols(colValue);
2446     DoneWithSizeDialog = True;
2447 }
2448 
sizeCancelCB(Widget w,XtPointer clientData,XtPointer callData)2449 static void sizeCancelCB(Widget w, XtPointer clientData, XtPointer callData)
2450 {
2451     DoneWithSizeDialog = True;
2452 }
2453 
2454 /*
2455 ** Present the user a dialog for setting tab related preferences, either as
2456 ** defaults, or for a specific window (pass "forWindow" as NULL to set default
2457 ** preference, or a window to set preferences for the specific window.
2458 */
TabsPrefDialog(Widget parent,WindowInfo * forWindow)2459 void TabsPrefDialog(Widget parent, WindowInfo *forWindow)
2460 {
2461     Widget form, selBox;
2462     Arg selBoxArgs[2];
2463     XmString s1;
2464     int emulate, emTabDist, useTabs, tabDist;
2465 
2466     XtSetArg(selBoxArgs[0], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
2467     XtSetArg(selBoxArgs[1], XmNautoUnmanage, False);
2468     selBox = CreatePromptDialog(parent, "customSize", selBoxArgs, 2);
2469     XtAddCallback(selBox, XmNokCallback, (XtCallbackProc)tabsOKCB, NULL);
2470     XtAddCallback(selBox, XmNcancelCallback, (XtCallbackProc)tabsCancelCB,NULL);
2471     XtAddCallback(selBox, XmNhelpCallback, (XtCallbackProc)tabsHelpCB,NULL);
2472     XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_TEXT));
2473     XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_SELECTION_LABEL));
2474     XtVaSetValues(XtParent(selBox), XmNtitle, "Tabs", NULL);
2475 
2476     form = XtVaCreateManagedWidget("form", xmFormWidgetClass, selBox, NULL);
2477 
2478     TabDistText = XtVaCreateManagedWidget("tabDistText", xmTextWidgetClass,
2479     	    form, XmNcolumns, 7,
2480     	    XmNtopAttachment, XmATTACH_FORM,
2481     	    XmNrightAttachment, XmATTACH_FORM, NULL);
2482     RemapDeleteKey(TabDistText);
2483     XtVaCreateManagedWidget("tabDistLabel", xmLabelGadgetClass, form,
2484     	    XmNlabelString, s1=XmStringCreateSimple(
2485     	    	"Tab spacing (for hardware tab characters)"),
2486 	    XmNmnemonic, 'T',
2487     	    XmNuserData, TabDistText,
2488     	    XmNtopAttachment, XmATTACH_FORM,
2489     	    XmNleftAttachment, XmATTACH_FORM,
2490     	    XmNrightAttachment, XmATTACH_WIDGET,
2491     	    XmNrightWidget, TabDistText,
2492 	    XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
2493 	    XmNbottomWidget, TabDistText, NULL);
2494     XmStringFree(s1);
2495 
2496     EmTabText = XtVaCreateManagedWidget("emTabText", xmTextWidgetClass, form,
2497     	    XmNcolumns, 7,
2498     	    XmNtopAttachment, XmATTACH_WIDGET,
2499     	    XmNtopWidget, TabDistText,
2500     	    XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET,
2501     	    XmNrightWidget, TabDistText, NULL);
2502     RemapDeleteKey(EmTabText);
2503     EmTabLabel = XtVaCreateManagedWidget("emTabLabel", xmLabelGadgetClass, form,
2504     	    XmNlabelString, s1=XmStringCreateSimple("Emulated tab spacing"),
2505 	    XmNmnemonic, 's',
2506     	    XmNuserData, EmTabText,
2507     	    XmNtopAttachment, XmATTACH_WIDGET,
2508     	    XmNtopWidget, TabDistText,
2509     	    XmNrightAttachment, XmATTACH_WIDGET,
2510     	    XmNrightWidget, EmTabText,
2511     	    XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
2512 	    XmNbottomWidget, EmTabText, NULL);
2513     XmStringFree(s1);
2514     EmTabToggle = XtVaCreateManagedWidget("emTabToggle",
2515     	    xmToggleButtonWidgetClass, form, XmNlabelString,
2516     	    	s1=XmStringCreateSimple("Emulate tabs"),
2517 	    XmNmnemonic, 'E',
2518     	    XmNtopAttachment, XmATTACH_WIDGET,
2519     	    XmNtopWidget, TabDistText,
2520     	    XmNleftAttachment, XmATTACH_FORM,
2521     	    XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
2522 	    XmNbottomWidget, EmTabText, NULL);
2523     XmStringFree(s1);
2524     XtAddCallback(EmTabToggle, XmNvalueChangedCallback, emTabsCB, NULL);
2525     UseTabsToggle = XtVaCreateManagedWidget("useTabsToggle",
2526     	    xmToggleButtonWidgetClass, form,
2527     	    XmNlabelString, s1=XmStringCreateSimple(
2528     	    	"Use tab characters in padding and emulated tabs"),
2529 	    XmNmnemonic, 'U',
2530     	    XmNtopAttachment, XmATTACH_WIDGET,
2531     	    XmNtopWidget, EmTabText,
2532     	    XmNtopOffset, 5,
2533     	    XmNleftAttachment, XmATTACH_FORM, NULL);
2534     XmStringFree(s1);
2535 
2536     /* Set default values */
2537     if (forWindow == NULL) {
2538     	emTabDist = GetPrefEmTabDist(PLAIN_LANGUAGE_MODE);
2539     	useTabs = GetPrefInsertTabs();
2540     	tabDist = GetPrefTabDist(PLAIN_LANGUAGE_MODE);
2541     } else {
2542     	XtVaGetValues(forWindow->textArea, textNemulateTabs, &emTabDist, NULL);
2543     	useTabs = forWindow->buffer->useTabs;
2544     	tabDist = BufGetTabDistance(forWindow->buffer);
2545     }
2546     emulate = emTabDist != 0;
2547     SetIntText(TabDistText, tabDist);
2548     XmToggleButtonSetState(EmTabToggle, emulate, True);
2549     if (emulate)
2550     	SetIntText(EmTabText, emTabDist);
2551     XmToggleButtonSetState(UseTabsToggle, useTabs, False);
2552     XtSetSensitive(EmTabText, emulate);
2553     XtSetSensitive(EmTabLabel, emulate);
2554 
2555     /* Handle mnemonic selection of buttons and focus to dialog */
2556     AddDialogMnemonicHandler(form, FALSE);
2557 
2558     /* Set the widget to get focus */
2559 #if XmVersion >= 1002
2560     XtVaSetValues(form, XmNinitialFocus, TabDistText, NULL);
2561 #endif
2562 
2563     /* put up dialog and wait for user to press ok or cancel */
2564     TabsDialogForWindow = forWindow;
2565     DoneWithTabsDialog = False;
2566     ManageDialogCenteredOnPointer(selBox);
2567     while (!DoneWithTabsDialog)
2568     {
2569        	XEvent event;
2570        	XtAppNextEvent(XtWidgetToApplicationContext(parent), &event);
2571        	ServerDispatchEvent(&event);
2572     }
2573 
2574     XtDestroyWidget(selBox);
2575 }
2576 
tabsOKCB(Widget w,XtPointer clientData,XtPointer callData)2577 static void tabsOKCB(Widget w, XtPointer clientData, XtPointer callData)
2578 {
2579     int emulate, useTabs, stat, tabDist, emTabDist;
2580     WindowInfo *window = TabsDialogForWindow;
2581 
2582     /* get the values that the user entered and make sure they're ok */
2583     emulate = XmToggleButtonGetState(EmTabToggle);
2584     useTabs = XmToggleButtonGetState(UseTabsToggle);
2585     stat = GetIntTextWarn(TabDistText, &tabDist, "tab spacing", True);
2586     if (stat != TEXT_READ_OK)
2587     	return;
2588 
2589     if (tabDist <= 0 || tabDist > MAX_EXP_CHAR_LEN)
2590     {
2591         DialogF(DF_WARN, TabDistText, 1, "Tab Spacing",
2592                 "Tab spacing out of range", "OK");
2593         return;
2594     }
2595 
2596     if (emulate) {
2597 	stat = GetIntTextWarn(EmTabText, &emTabDist, "emulated tab spacing",True);
2598 	if (stat != TEXT_READ_OK)
2599 	    return;
2600 
2601         if (emTabDist <= 0 || tabDist >= 1000)
2602         {
2603             DialogF(DF_WARN, EmTabText, 1, "Tab Spacing",
2604                     "Emulated tab spacing out of range", "OK");
2605             return;
2606         }
2607     } else
2608     	emTabDist = 0;
2609 
2610 #ifdef SGI_CUSTOM
2611     /* Ask the user about saving as a default preference */
2612     if (TabsDialogForWindow != NULL) {
2613 	int setDefault;
2614 	if (!shortPrefToDefault(window->shell, "Tab Settings", &setDefault)) {
2615 	    DoneWithTabsDialog = True;
2616     	    return;
2617 	}
2618 	if (setDefault) {
2619     	    SetPrefTabDist(tabDist);
2620     	    SetPrefEmTabDist(emTabDist);
2621     	    SetPrefInsertTabs(useTabs);
2622 	    SaveNEditPrefs(window->shell, GetPrefShortMenus());
2623 	}
2624     }
2625 #endif
2626 
2627     /* Set the value in either the requested window or default preferences */
2628     if (TabsDialogForWindow == NULL) {
2629     	SetPrefTabDist(tabDist);
2630     	SetPrefEmTabDist(emTabDist);
2631     	SetPrefInsertTabs(useTabs);
2632     } else {
2633         char *params[1];
2634         char numStr[25];
2635 
2636         params[0] = numStr;
2637         sprintf(numStr, "%d", tabDist);
2638         XtCallActionProc(window->textArea, "set_tab_dist", NULL, params, 1);
2639         params[0] = numStr;
2640         sprintf(numStr, "%d", emTabDist);
2641         XtCallActionProc(window->textArea, "set_em_tab_dist", NULL, params, 1);
2642         params[0] = numStr;
2643         sprintf(numStr, "%d", useTabs);
2644         XtCallActionProc(window->textArea, "set_use_tabs", NULL, params, 1);
2645 /*
2646     	setTabDist(window, tabDist);
2647     	setEmTabDist(window, emTabDist);
2648        	window->buffer->useTabs = useTabs;
2649 */
2650     }
2651     DoneWithTabsDialog = True;
2652 }
2653 
tabsCancelCB(Widget w,XtPointer clientData,XtPointer callData)2654 static void tabsCancelCB(Widget w, XtPointer clientData, XtPointer callData)
2655 {
2656     DoneWithTabsDialog = True;
2657 }
2658 
tabsHelpCB(Widget w,XtPointer clientData,XtPointer callData)2659 static void tabsHelpCB(Widget w, XtPointer clientData, XtPointer callData)
2660 {
2661     Help(HELP_TABS_DIALOG);
2662 }
2663 
emTabsCB(Widget w,XtPointer clientData,XtPointer callData)2664 static void emTabsCB(Widget w, XtPointer clientData, XtPointer callData)
2665 {
2666     int state = XmToggleButtonGetState(w);
2667 
2668     XtSetSensitive(EmTabLabel, state);
2669     XtSetSensitive(EmTabText, state);
2670 }
2671 
2672 /*
2673 ** Present the user a dialog for setting wrap margin.
2674 */
WrapMarginDialog(Widget parent,WindowInfo * forWindow)2675 void WrapMarginDialog(Widget parent, WindowInfo *forWindow)
2676 {
2677     Widget form, selBox;
2678     Arg selBoxArgs[2];
2679     XmString s1;
2680     int margin;
2681 
2682     XtSetArg(selBoxArgs[0], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
2683     XtSetArg(selBoxArgs[1], XmNautoUnmanage, False);
2684     selBox = CreatePromptDialog(parent, "wrapMargin", selBoxArgs, 2);
2685     XtAddCallback(selBox, XmNokCallback, (XtCallbackProc)wrapOKCB, NULL);
2686     XtAddCallback(selBox, XmNcancelCallback, (XtCallbackProc)wrapCancelCB,NULL);
2687     XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_TEXT));
2688     XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_SELECTION_LABEL));
2689     XtUnmanageChild(XmSelectionBoxGetChild(selBox, XmDIALOG_HELP_BUTTON));
2690     XtVaSetValues(XtParent(selBox), XmNtitle, "Wrap Margin", NULL);
2691 
2692     form = XtVaCreateManagedWidget("form", xmFormWidgetClass, selBox, NULL);
2693 
2694     WrapWindowToggle = XtVaCreateManagedWidget("wrapWindowToggle",
2695     	    xmToggleButtonWidgetClass, form, XmNlabelString,
2696     	    	s1=XmStringCreateSimple("Wrap and Fill at width of window"),
2697 	    XmNmnemonic, 'W',
2698     	    XmNtopAttachment, XmATTACH_FORM,
2699     	    XmNleftAttachment, XmATTACH_FORM, NULL);
2700     XmStringFree(s1);
2701     XtAddCallback(WrapWindowToggle, XmNvalueChangedCallback, wrapWindowCB,NULL);
2702     WrapText = XtVaCreateManagedWidget("wrapText", xmTextWidgetClass, form,
2703     	    XmNcolumns, 5,
2704     	    XmNtopAttachment, XmATTACH_WIDGET,
2705     	    XmNtopWidget, WrapWindowToggle,
2706     	    XmNrightAttachment, XmATTACH_FORM, NULL);
2707     RemapDeleteKey(WrapText);
2708     WrapTextLabel = XtVaCreateManagedWidget("wrapMarginLabel",
2709     	    xmLabelGadgetClass, form,
2710     	    XmNlabelString, s1=XmStringCreateSimple(
2711     	    	"Margin for Wrap and Fill"),
2712 	    XmNmnemonic, 'M',
2713     	    XmNuserData, WrapText,
2714     	    XmNtopAttachment, XmATTACH_WIDGET,
2715     	    XmNtopWidget, WrapWindowToggle,
2716     	    XmNleftAttachment, XmATTACH_FORM,
2717     	    XmNrightAttachment, XmATTACH_WIDGET,
2718     	    XmNrightWidget, WrapText,
2719 	    XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
2720 	    XmNbottomWidget, WrapText, NULL);
2721     XmStringFree(s1);
2722 
2723     /* Set default value */
2724     if (forWindow == NULL)
2725     	margin = GetPrefWrapMargin();
2726     else
2727     	XtVaGetValues(forWindow->textArea, textNwrapMargin, &margin, NULL);
2728     XmToggleButtonSetState(WrapWindowToggle, margin==0, True);
2729     if (margin != 0)
2730     	SetIntText(WrapText, margin);
2731     XtSetSensitive(WrapText, margin!=0);
2732     XtSetSensitive(WrapTextLabel, margin!=0);
2733 
2734     /* Handle mnemonic selection of buttons and focus to dialog */
2735     AddDialogMnemonicHandler(form, FALSE);
2736 
2737     /* put up dialog and wait for user to press ok or cancel */
2738     WrapDialogForWindow = forWindow;
2739     DoneWithWrapDialog = False;
2740     ManageDialogCenteredOnPointer(selBox);
2741     while (!DoneWithWrapDialog)
2742     {
2743        	XEvent event;
2744        	XtAppNextEvent(XtWidgetToApplicationContext(parent), &event);
2745        	ServerDispatchEvent(&event);
2746     }
2747 
2748     XtDestroyWidget(selBox);
2749 }
2750 
wrapOKCB(Widget w,XtPointer clientData,XtPointer callData)2751 static void wrapOKCB(Widget w, XtPointer clientData, XtPointer callData)
2752 {
2753     int wrapAtWindow, margin, stat;
2754     WindowInfo *window = WrapDialogForWindow;
2755 
2756     /* get the values that the user entered and make sure they're ok */
2757     wrapAtWindow = XmToggleButtonGetState(WrapWindowToggle);
2758     if (wrapAtWindow)
2759     	margin = 0;
2760     else {
2761 	stat = GetIntTextWarn(WrapText, &margin, "wrap Margin", True);
2762 	if (stat != TEXT_READ_OK)
2763     	    return;
2764 
2765        if (margin <= 0 || margin >= 1000)
2766        {
2767            DialogF(DF_WARN, WrapText, 1, "Wrap Margin",
2768                    "Wrap margin out of range", "OK");
2769            return;
2770        }
2771 
2772     }
2773 
2774 #ifdef SGI_CUSTOM
2775     /* Ask the user about saving as a default preference */
2776     if (WrapDialogForWindow != NULL) {
2777 	int setDefault;
2778 	if (!shortPrefToDefault(window->shell, "Wrap Margin Settings",
2779 	    	&setDefault)) {
2780 	    DoneWithWrapDialog = True;
2781     	    return;
2782 	}
2783 	if (setDefault) {
2784     	    SetPrefWrapMargin(margin);
2785 	    SaveNEditPrefs(window->shell, GetPrefShortMenus());
2786 	}
2787     }
2788 #endif
2789 
2790     /* Set the value in either the requested window or default preferences */
2791     if (WrapDialogForWindow == NULL)
2792     	SetPrefWrapMargin(margin);
2793     else {
2794         char *params[1];
2795         char marginStr[25];
2796         sprintf(marginStr, "%d", margin);
2797         params[0] = marginStr;
2798         XtCallActionProc(window->textArea, "set_wrap_margin", NULL, params, 1);
2799     }
2800     DoneWithWrapDialog = True;
2801 }
2802 
wrapCancelCB(Widget w,XtPointer clientData,XtPointer callData)2803 static void wrapCancelCB(Widget w, XtPointer clientData, XtPointer callData)
2804 {
2805     DoneWithWrapDialog = True;
2806 }
2807 
wrapWindowCB(Widget w,XtPointer clientData,XtPointer callData)2808 static void wrapWindowCB(Widget w, XtPointer clientData, XtPointer callData)
2809 {
2810     int wrapAtWindow = XmToggleButtonGetState(w);
2811 
2812     XtSetSensitive(WrapTextLabel, !wrapAtWindow);
2813     XtSetSensitive(WrapText, !wrapAtWindow);
2814 }
2815 
2816 /*
2817 **  Create and show a dialog for selecting the shell
2818 */
SelectShellDialog(Widget parent,WindowInfo * forWindow)2819 void SelectShellDialog(Widget parent, WindowInfo* forWindow)
2820 {
2821     Widget shellSelDialog;
2822     Arg shellSelDialogArgs[2];
2823     XmString label;
2824 
2825     /*  Set up the dialog.  */
2826     XtSetArg(shellSelDialogArgs[0],
2827             XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
2828     XtSetArg(shellSelDialogArgs[1], XmNautoUnmanage, False);
2829     shellSelDialog = CreatePromptDialog(parent, "shellSelDialog",
2830             shellSelDialogArgs, 2);
2831 
2832     /*  Fix dialog to our liking.  */
2833     XtVaSetValues(XtParent(shellSelDialog), XmNtitle, "Command Shell", NULL);
2834     XtAddCallback(shellSelDialog, XmNokCallback, (XtCallbackProc) shellSelOKCB,
2835             shellSelDialog);
2836     XtAddCallback(shellSelDialog, XmNcancelCallback,
2837             (XtCallbackProc) shellSelCancelCB, NULL);
2838     XtUnmanageChild(XmSelectionBoxGetChild(shellSelDialog, XmDIALOG_HELP_BUTTON));
2839     label = XmStringCreateLocalized("Enter shell path:");
2840     XtVaSetValues(shellSelDialog, XmNselectionLabelString, label, NULL);
2841     XmStringFree(label);
2842 
2843     /*  Set dialog's text to the current setting.  */
2844     XmTextSetString(XmSelectionBoxGetChild(shellSelDialog, XmDIALOG_TEXT),
2845             (char*) GetPrefShell());
2846 
2847     DoneWithShellSelDialog = False;
2848 
2849     /*  Show dialog and wait until the user made her choice.  */
2850     ManageDialogCenteredOnPointer(shellSelDialog);
2851     while (!DoneWithShellSelDialog) {
2852         XEvent event;
2853         XtAppNextEvent(XtWidgetToApplicationContext(parent), &event);
2854         ServerDispatchEvent(&event);
2855     }
2856 
2857     XtDestroyWidget(shellSelDialog);
2858 }
2859 
shellSelOKCB(Widget widget,XtPointer clientData,XtPointer callData)2860 static void shellSelOKCB(Widget widget, XtPointer clientData,
2861         XtPointer callData)
2862 {
2863     Widget shellSelDialog = (Widget) clientData;
2864     String shellName = (char*)NEditMalloc(MAXPATHLEN);
2865     struct stat attribute;
2866     unsigned dlgResult;
2867 
2868     /*  Leave with a warning if the dialog is not up.  */
2869     if (!XtIsRealized(shellSelDialog)) {
2870         fprintf(stderr, "nedit: Callback shellSelOKCB() illegally called.\n");
2871         return;
2872     }
2873 
2874     /*  Get the string that the user entered and make sure it's ok.  */
2875     shellName = XmTextGetString(XmSelectionBoxGetChild(shellSelDialog,
2876             XmDIALOG_TEXT));
2877 
2878     if (-1 == stat(shellName, &attribute)) {
2879         dlgResult = DialogF(DF_WARN, shellSelDialog, 2, "Command Shell",
2880                 "The selected shell is not available.\nDo you want to use it anyway?",
2881                 "OK", "Cancel");
2882         if (1 != dlgResult) {
2883             return;
2884         }
2885     }
2886 
2887     SetPrefShell(shellName);
2888     NEditFree(shellName);
2889 
2890     DoneWithShellSelDialog = True;
2891 }
2892 
shellSelCancelCB(Widget widgget,XtPointer clientData,XtPointer callData)2893 static void shellSelCancelCB(Widget widgget, XtPointer clientData,
2894         XtPointer callData)
2895 {
2896     DoneWithShellSelDialog = True;
2897 }
2898 
2899 /*
2900 ** Present a dialog for editing language mode information
2901 */
EditLanguageModes(void)2902 void EditLanguageModes(void)
2903 {
2904 #define LIST_RIGHT 40
2905 #define LEFT_MARGIN_POS 1
2906 #define RIGHT_MARGIN_POS 99
2907 #define H_MARGIN 5
2908     Widget form, nameLbl, topLbl, extLbl, recogLbl, delimitLbl, defTipsLbl;
2909     Widget okBtn, applyBtn, closeBtn;
2910     Widget overrideFrame, overrideForm, delimitForm;
2911     Widget tabForm, tabLbl, indentBox, wrapBox;
2912     XmString s1;
2913     int i, ac;
2914     Arg args[20];
2915 
2916     /* if the dialog is already displayed, just pop it to the top and return */
2917     if (LMDialog.shell != NULL) {
2918     	RaiseDialogWindow(LMDialog.shell);
2919     	return;
2920     }
2921 
2922     LMDialog.languageModeList = (languageModeRec **)NEditMalloc(
2923     	    sizeof(languageModeRec *) * MAX_LANGUAGE_MODES);
2924     for (i=0; i<NLanguageModes; i++)
2925     	LMDialog.languageModeList[i] = copyLanguageModeRec(LanguageModes[i]);
2926     LMDialog.nLanguageModes = NLanguageModes;
2927 
2928     /* Create a form widget in an application shell */
2929     ac = 0;
2930     XtSetArg(args[ac], XmNdeleteResponse, XmDO_NOTHING); ac++;
2931     XtSetArg(args[ac], XmNiconName, "NEdit Language Modes"); ac++;
2932     XtSetArg(args[ac], XmNtitle, "Language Modes"); ac++;
2933     LMDialog.shell = CreateWidget(TheAppShell, "langModes",
2934 	    topLevelShellWidgetClass, args, ac);
2935     AddSmallIcon(LMDialog.shell);
2936     form = XtVaCreateManagedWidget("editLanguageModes", xmFormWidgetClass,
2937 	    LMDialog.shell, XmNautoUnmanage, False,
2938 	    XmNresizePolicy, XmRESIZE_NONE, NULL);
2939     XtAddCallback(form, XmNdestroyCallback, lmDestroyCB, NULL);
2940     AddMotifCloseCallback(LMDialog.shell, lmCloseCB, NULL);
2941 
2942     topLbl = XtVaCreateManagedWidget("topLabel", xmLabelGadgetClass, form,
2943     	    XmNlabelString, s1=MKSTRING(
2944 "To modify the properties of an existing language mode, select the name from\n\
2945 the list on the left.  To add a new language, select \"New\" from the list."),
2946 	    XmNmnemonic, 'N',
2947 	    XmNtopAttachment, XmATTACH_POSITION,
2948 	    XmNtopPosition, 2,
2949 	    XmNleftAttachment, XmATTACH_POSITION,
2950 	    XmNleftPosition, LEFT_MARGIN_POS,
2951 	    XmNrightAttachment, XmATTACH_POSITION,
2952 	    XmNrightPosition, RIGHT_MARGIN_POS, NULL);
2953     XmStringFree(s1);
2954 
2955     nameLbl = XtVaCreateManagedWidget("nameLbl", xmLabelGadgetClass, form,
2956     	    XmNlabelString, s1=XmStringCreateSimple("Name"),
2957 	    XmNmnemonic, 'm',
2958     	    XmNalignment, XmALIGNMENT_BEGINNING,
2959 	    XmNleftAttachment, XmATTACH_POSITION,
2960     	    XmNleftPosition, LIST_RIGHT,
2961 	    XmNtopAttachment, XmATTACH_WIDGET,
2962 	    XmNtopOffset, H_MARGIN,
2963 	    XmNtopWidget, topLbl, NULL);
2964     XmStringFree(s1);
2965 
2966     LMDialog.nameW = XtVaCreateManagedWidget("name", xmTextWidgetClass, form,
2967     	    XmNcolumns, 15,
2968 	    XmNleftAttachment, XmATTACH_POSITION,
2969 	    XmNleftPosition, LIST_RIGHT,
2970 	    XmNtopAttachment, XmATTACH_WIDGET,
2971 	    XmNtopWidget, nameLbl,
2972 	    XmNrightAttachment, XmATTACH_POSITION,
2973 	    XmNrightPosition, (RIGHT_MARGIN_POS + LIST_RIGHT)/2, NULL);
2974     RemapDeleteKey(LMDialog.nameW);
2975     XtVaSetValues(nameLbl, XmNuserData, LMDialog.nameW, NULL);
2976 
2977     extLbl = XtVaCreateManagedWidget("extLbl", xmLabelGadgetClass, form,
2978     	    XmNlabelString,
2979     	    	s1=XmStringCreateSimple("File extensions (separate w/ space)"),
2980     	    XmNmnemonic, 'F',
2981     	    XmNalignment, XmALIGNMENT_BEGINNING,
2982 	    XmNleftAttachment, XmATTACH_POSITION,
2983     	    XmNleftPosition, LIST_RIGHT,
2984 	    XmNtopAttachment, XmATTACH_WIDGET,
2985 	    XmNtopOffset, H_MARGIN,
2986 	    XmNtopWidget, LMDialog.nameW, NULL);
2987     XmStringFree(s1);
2988 
2989     LMDialog.extW = XtVaCreateManagedWidget("ext", xmTextWidgetClass, form,
2990 	    XmNleftAttachment, XmATTACH_POSITION,
2991 	    XmNleftPosition, LIST_RIGHT,
2992 	    XmNtopAttachment, XmATTACH_WIDGET,
2993 	    XmNtopWidget, extLbl,
2994 	    XmNrightAttachment, XmATTACH_POSITION,
2995 	    XmNrightPosition, RIGHT_MARGIN_POS, NULL);
2996     RemapDeleteKey(LMDialog.extW);
2997     XtVaSetValues(extLbl, XmNuserData, LMDialog.extW, NULL);
2998 
2999     recogLbl = XtVaCreateManagedWidget("recogLbl", xmLabelGadgetClass, form,
3000     	    XmNlabelString, s1=MKSTRING(
3001 "Recognition regular expression (applied to first 200\n\
3002 characters of file to determine type from content)"),
3003     	    XmNalignment, XmALIGNMENT_BEGINNING,
3004     	    XmNmnemonic, 'R',
3005 	    XmNleftAttachment, XmATTACH_POSITION,
3006     	    XmNleftPosition, LIST_RIGHT,
3007 	    XmNtopAttachment, XmATTACH_WIDGET,
3008 	    XmNtopOffset, H_MARGIN,
3009 	    XmNtopWidget, LMDialog.extW, NULL);
3010     XmStringFree(s1);
3011 
3012     LMDialog.recogW = XtVaCreateManagedWidget("recog", xmTextWidgetClass, form,
3013 	    XmNleftAttachment, XmATTACH_POSITION,
3014 	    XmNleftPosition, LIST_RIGHT,
3015 	    XmNtopAttachment, XmATTACH_WIDGET,
3016 	    XmNtopWidget, recogLbl,
3017 	    XmNrightAttachment, XmATTACH_POSITION,
3018 	    XmNrightPosition, RIGHT_MARGIN_POS, NULL);
3019     RemapDeleteKey(LMDialog.recogW);
3020     XtVaSetValues(recogLbl, XmNuserData, LMDialog.recogW, NULL);
3021 
3022     defTipsLbl = XtVaCreateManagedWidget("defTipsLbl", xmLabelGadgetClass, form,
3023     	    XmNlabelString, s1=MKSTRING(
3024 "Default calltips file(s) (separate w/colons)"),
3025     	    XmNalignment, XmALIGNMENT_BEGINNING,
3026     	    XmNmnemonic, 'c',
3027 	    XmNleftAttachment, XmATTACH_POSITION,
3028     	    XmNleftPosition, LIST_RIGHT,
3029 	    XmNtopAttachment, XmATTACH_WIDGET,
3030 	    XmNtopOffset, H_MARGIN,
3031 	    XmNtopWidget, LMDialog.recogW, NULL);
3032     XmStringFree(s1);
3033 
3034     LMDialog.defTipsW = XtVaCreateManagedWidget("defTips", xmTextWidgetClass,
3035             form,
3036 	    XmNleftAttachment, XmATTACH_POSITION,
3037 	    XmNleftPosition, LIST_RIGHT,
3038 	    XmNtopAttachment, XmATTACH_WIDGET,
3039 	    XmNtopWidget, defTipsLbl,
3040 	    XmNrightAttachment, XmATTACH_POSITION,
3041 	    XmNrightPosition, RIGHT_MARGIN_POS, NULL);
3042     RemapDeleteKey(LMDialog.defTipsW);
3043     XtVaSetValues(defTipsLbl, XmNuserData, LMDialog.defTipsW, NULL);
3044 
3045     okBtn = XtVaCreateManagedWidget("ok", xmPushButtonWidgetClass, form,
3046             XmNlabelString, s1=XmStringCreateSimple("OK"),
3047             XmNmarginWidth, BUTTON_WIDTH_MARGIN,
3048     	    XmNleftAttachment, XmATTACH_POSITION,
3049     	    XmNleftPosition, 10,
3050     	    XmNrightAttachment, XmATTACH_POSITION,
3051     	    XmNrightPosition, 30,
3052     	    XmNbottomAttachment, XmATTACH_POSITION,
3053     	    XmNbottomPosition, 99, NULL);
3054     XtAddCallback(okBtn, XmNactivateCallback, lmOkCB, NULL);
3055     XmStringFree(s1);
3056 
3057     applyBtn = XtVaCreateManagedWidget("apply", xmPushButtonWidgetClass, form,
3058     	    XmNlabelString, s1=XmStringCreateSimple("Apply"),
3059     	    XmNmnemonic, 'A',
3060     	    XmNleftAttachment, XmATTACH_POSITION,
3061     	    XmNleftPosition, 40,
3062     	    XmNrightAttachment, XmATTACH_POSITION,
3063     	    XmNrightPosition, 60,
3064     	    XmNbottomAttachment, XmATTACH_POSITION,
3065     	    XmNbottomPosition, 99, NULL);
3066     XtAddCallback(applyBtn, XmNactivateCallback, lmApplyCB, NULL);
3067     XmStringFree(s1);
3068 
3069     closeBtn = XtVaCreateManagedWidget("close",xmPushButtonWidgetClass,form,
3070             XmNlabelString, s1=XmStringCreateSimple("Close"),
3071     	    XmNleftAttachment, XmATTACH_POSITION,
3072     	    XmNleftPosition, 70,
3073     	    XmNrightAttachment, XmATTACH_POSITION,
3074     	    XmNrightPosition, 90,
3075     	    XmNbottomAttachment, XmATTACH_POSITION,
3076     	    XmNbottomPosition, 99, NULL);
3077     XtAddCallback(closeBtn, XmNactivateCallback, lmCloseCB, NULL);
3078     XmStringFree(s1);
3079 
3080     overrideFrame = XtVaCreateManagedWidget("overrideFrame",
3081     	    xmFrameWidgetClass, form,
3082 	    XmNleftAttachment, XmATTACH_POSITION,
3083 	    XmNleftPosition, LEFT_MARGIN_POS,
3084 	    XmNrightAttachment, XmATTACH_POSITION,
3085 	    XmNrightPosition, RIGHT_MARGIN_POS,
3086 	    XmNbottomAttachment, XmATTACH_WIDGET,
3087             XmNbottomWidget, closeBtn,
3088 	    XmNbottomOffset, H_MARGIN, NULL);
3089     overrideForm = XtVaCreateManagedWidget("overrideForm", xmFormWidgetClass,
3090 	    overrideFrame, NULL);
3091     XtVaCreateManagedWidget("overrideLbl", xmLabelGadgetClass, overrideFrame,
3092     	    XmNlabelString, s1=XmStringCreateSimple("Override Defaults"),
3093 	    XmNchildType, XmFRAME_TITLE_CHILD,
3094 	    XmNchildHorizontalAlignment, XmALIGNMENT_CENTER, NULL);
3095     XmStringFree(s1);
3096 
3097     delimitForm = XtVaCreateManagedWidget("delimitForm", xmFormWidgetClass,
3098 	    overrideForm,
3099 	    XmNleftAttachment, XmATTACH_POSITION,
3100 	    XmNleftPosition, LEFT_MARGIN_POS,
3101 	    XmNtopAttachment, XmATTACH_FORM,
3102 	    XmNtopOffset, H_MARGIN,
3103 	    XmNrightAttachment, XmATTACH_POSITION,
3104 	    XmNrightPosition, RIGHT_MARGIN_POS, NULL);
3105     delimitLbl = XtVaCreateManagedWidget("delimitLbl", xmLabelGadgetClass,
3106     	    delimitForm,
3107     	    XmNlabelString, s1=XmStringCreateSimple("Word delimiters"),
3108     	    XmNmnemonic, 'W',
3109 	    XmNleftAttachment, XmATTACH_FORM,
3110 	    XmNtopAttachment, XmATTACH_FORM,
3111 	    XmNbottomAttachment, XmATTACH_FORM, NULL);
3112     XmStringFree(s1);
3113     LMDialog.delimitW = XtVaCreateManagedWidget("delimit", xmTextWidgetClass,
3114     	    delimitForm,
3115 	    XmNtopAttachment, XmATTACH_FORM,
3116 	    XmNleftAttachment, XmATTACH_WIDGET,
3117 	    XmNleftWidget, delimitLbl,
3118 	    XmNrightAttachment, XmATTACH_FORM,
3119 	    XmNbottomAttachment, XmATTACH_FORM, NULL);
3120     RemapDeleteKey(LMDialog.delimitW);
3121     XtVaSetValues(delimitLbl, XmNuserData, LMDialog.delimitW, NULL);
3122 
3123     tabForm = XtVaCreateManagedWidget("tabForm", xmFormWidgetClass,
3124 	    overrideForm,
3125 	    XmNleftAttachment, XmATTACH_POSITION,
3126 	    XmNleftPosition, LEFT_MARGIN_POS,
3127 	    XmNtopAttachment, XmATTACH_WIDGET,
3128 	    XmNtopWidget, delimitForm,
3129 	    XmNtopOffset, H_MARGIN,
3130 	    XmNrightAttachment, XmATTACH_POSITION,
3131 	    XmNrightPosition, RIGHT_MARGIN_POS, NULL);
3132     tabLbl = XtVaCreateManagedWidget("tabLbl", xmLabelGadgetClass, tabForm,
3133     	    XmNlabelString, s1=XmStringCreateSimple(
3134     	    	"Alternative hardware tab spacing"),
3135     	    XmNmnemonic, 't',
3136 	    XmNleftAttachment, XmATTACH_FORM,
3137 	    XmNtopAttachment, XmATTACH_FORM,
3138 	    XmNbottomAttachment, XmATTACH_FORM, NULL);
3139     XmStringFree(s1);
3140     LMDialog.tabW = XtVaCreateManagedWidget("delimit", xmTextWidgetClass,
3141     	    tabForm,
3142     	    XmNcolumns, 3,
3143 	    XmNtopAttachment, XmATTACH_FORM,
3144 	    XmNleftAttachment, XmATTACH_WIDGET,
3145 	    XmNleftWidget, tabLbl,
3146 	    XmNbottomAttachment, XmATTACH_FORM, NULL);
3147     RemapDeleteKey(LMDialog.tabW);
3148     XtVaSetValues(tabLbl, XmNuserData, LMDialog.tabW, NULL);
3149     LMDialog.emTabW = XtVaCreateManagedWidget("delimit", xmTextWidgetClass,
3150     	    tabForm,
3151     	    XmNcolumns, 3,
3152 	    XmNtopAttachment, XmATTACH_FORM,
3153 	    XmNrightAttachment, XmATTACH_FORM,
3154 	    XmNbottomAttachment, XmATTACH_FORM, NULL);
3155     RemapDeleteKey(LMDialog.emTabW);
3156     XtVaCreateManagedWidget("emTabLbl", xmLabelGadgetClass, tabForm,
3157     	    XmNlabelString,
3158     	    s1=XmStringCreateSimple("Alternative emulated tab spacing"),
3159     	    XmNalignment, XmALIGNMENT_END,
3160     	    XmNmnemonic, 'e',
3161 	    XmNuserData, LMDialog.emTabW,
3162 	    XmNleftAttachment, XmATTACH_WIDGET,
3163 	    XmNleftWidget, LMDialog.tabW,
3164 	    XmNrightAttachment, XmATTACH_WIDGET,
3165 	    XmNrightWidget, LMDialog.emTabW,
3166 	    XmNtopAttachment, XmATTACH_FORM,
3167 	    XmNbottomAttachment, XmATTACH_FORM, NULL);
3168     XmStringFree(s1);
3169 
3170     indentBox = XtVaCreateManagedWidget("indentBox", xmRowColumnWidgetClass,
3171     	    overrideForm,
3172     	    XmNorientation, XmHORIZONTAL,
3173     	    XmNpacking, XmPACK_TIGHT,
3174     	    XmNradioBehavior, True,
3175 	    XmNleftAttachment, XmATTACH_POSITION,
3176     	    XmNleftPosition, LEFT_MARGIN_POS,
3177 	    XmNtopAttachment, XmATTACH_WIDGET,
3178 	    XmNtopWidget, tabForm,
3179 	    XmNtopOffset, H_MARGIN, NULL);
3180     LMDialog.defaultIndentW = XtVaCreateManagedWidget("defaultIndent",
3181     	    xmToggleButtonWidgetClass, indentBox,
3182     	    XmNset, True,
3183     	    XmNmarginHeight, 0,
3184     	    XmNlabelString, s1=XmStringCreateSimple("Default indent style"),
3185     	    XmNmnemonic, 'D', NULL);
3186     XmStringFree(s1);
3187     LMDialog.noIndentW = XtVaCreateManagedWidget("noIndent",
3188     	    xmToggleButtonWidgetClass, indentBox,
3189     	    XmNmarginHeight, 0,
3190     	    XmNlabelString, s1=XmStringCreateSimple("No automatic indent"),
3191     	    XmNmnemonic, 'N', NULL);
3192     XmStringFree(s1);
3193     LMDialog.autoIndentW = XtVaCreateManagedWidget("autoIndent",
3194     	    xmToggleButtonWidgetClass, indentBox,
3195     	    XmNmarginHeight, 0,
3196     	    XmNlabelString, s1=XmStringCreateSimple("Auto-indent"),
3197     	    XmNmnemonic, 'A', NULL);
3198     XmStringFree(s1);
3199     LMDialog.smartIndentW = XtVaCreateManagedWidget("smartIndent",
3200     	    xmToggleButtonWidgetClass, indentBox,
3201     	    XmNmarginHeight, 0,
3202     	    XmNlabelString, s1=XmStringCreateSimple("Smart-indent"),
3203     	    XmNmnemonic, 'S', NULL);
3204     XmStringFree(s1);
3205 
3206     wrapBox = XtVaCreateManagedWidget("wrapBox", xmRowColumnWidgetClass,
3207     	    overrideForm,
3208     	    XmNorientation, XmHORIZONTAL,
3209     	    XmNpacking, XmPACK_TIGHT,
3210     	    XmNradioBehavior, True,
3211 	    XmNleftAttachment, XmATTACH_POSITION,
3212     	    XmNleftPosition, LEFT_MARGIN_POS,
3213 	    XmNtopAttachment, XmATTACH_WIDGET,
3214 	    XmNtopWidget, indentBox,
3215 	    XmNtopOffset, H_MARGIN,
3216 	    XmNbottomAttachment, XmATTACH_FORM,
3217 	    XmNbottomOffset, H_MARGIN, NULL);
3218     LMDialog.defaultWrapW = XtVaCreateManagedWidget("defaultWrap",
3219     	    xmToggleButtonWidgetClass, wrapBox,
3220     	    XmNset, True,
3221     	    XmNmarginHeight, 0,
3222     	    XmNlabelString, s1=XmStringCreateSimple("Default wrap style"),
3223     	    XmNmnemonic, 'D', NULL);
3224     XmStringFree(s1);
3225     LMDialog.noWrapW = XtVaCreateManagedWidget("noWrap",
3226     	    xmToggleButtonWidgetClass, wrapBox,
3227     	    XmNmarginHeight, 0,
3228     	    XmNlabelString, s1=XmStringCreateSimple("No wrapping"),
3229     	    XmNmnemonic, 'N', NULL);
3230     XmStringFree(s1);
3231     LMDialog.newlineWrapW = XtVaCreateManagedWidget("newlineWrap",
3232     	    xmToggleButtonWidgetClass, wrapBox,
3233     	    XmNmarginHeight, 0,
3234     	    XmNlabelString, s1=XmStringCreateSimple("Auto newline wrap"),
3235     	    XmNmnemonic, 'A', NULL);
3236     XmStringFree(s1);
3237     LMDialog.contWrapW = XtVaCreateManagedWidget("contWrap",
3238     	    xmToggleButtonWidgetClass, wrapBox,
3239     	    XmNmarginHeight, 0,
3240     	    XmNlabelString, s1=XmStringCreateSimple("Continuous wrap"),
3241     	    XmNmnemonic, 'C', NULL);
3242     XmStringFree(s1);
3243 
3244     XtVaCreateManagedWidget("stretchForm", xmFormWidgetClass, form,
3245 	    XmNtopAttachment, XmATTACH_WIDGET,
3246 	    XmNtopWidget, LMDialog.defTipsW,
3247 	    XmNleftAttachment, XmATTACH_POSITION,
3248 	    XmNleftPosition, LIST_RIGHT,
3249 	    XmNrightAttachment, XmATTACH_POSITION,
3250 	    XmNrightPosition, RIGHT_MARGIN_POS,
3251 	    XmNbottomAttachment, XmATTACH_WIDGET,
3252 	    XmNbottomWidget, overrideFrame,
3253 	    XmNbottomOffset, H_MARGIN*2, NULL);
3254 
3255     ac = 0;
3256     XtSetArg(args[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
3257     XtSetArg(args[ac], XmNtopOffset, H_MARGIN); ac++;
3258     XtSetArg(args[ac], XmNtopWidget, topLbl); ac++;
3259     XtSetArg(args[ac], XmNleftAttachment, XmATTACH_POSITION); ac++;
3260     XtSetArg(args[ac], XmNleftPosition, LEFT_MARGIN_POS); ac++;
3261     XtSetArg(args[ac], XmNrightAttachment, XmATTACH_POSITION); ac++;
3262     XtSetArg(args[ac], XmNrightPosition, LIST_RIGHT-1); ac++;
3263     XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
3264     XtSetArg(args[ac], XmNbottomWidget, overrideFrame); ac++;
3265     XtSetArg(args[ac], XmNbottomOffset, H_MARGIN*2); ac++;
3266     LMDialog.managedListW = CreateManagedList(form, "list", args, ac,
3267     	    (void **)LMDialog.languageModeList, &LMDialog.nLanguageModes,
3268     	    MAX_LANGUAGE_MODES, 15, lmGetDisplayedCB, NULL, lmSetDisplayedCB,
3269     	    NULL, lmFreeItemCB);
3270     AddDeleteConfirmCB(LMDialog.managedListW, lmDeleteConfirmCB, NULL);
3271     XtVaSetValues(topLbl, XmNuserData, LMDialog.managedListW, NULL);
3272 
3273     /* Set initial default button */
3274     XtVaSetValues(form, XmNdefaultButton, okBtn, NULL);
3275     XtVaSetValues(form, XmNcancelButton, closeBtn, NULL);
3276 
3277     /* Handle mnemonic selection of buttons and focus to dialog */
3278     AddDialogMnemonicHandler(form, FALSE);
3279 
3280     /* Realize all of the widgets in the new dialog */
3281     RealizeWithoutForcingPosition(LMDialog.shell);
3282 }
3283 
lmDestroyCB(Widget w,XtPointer clientData,XtPointer callData)3284 static void lmDestroyCB(Widget w, XtPointer clientData, XtPointer callData)
3285 {
3286     int i;
3287 
3288     for (i=0; i<LMDialog.nLanguageModes; i++)
3289     	freeLanguageModeRec(LMDialog.languageModeList[i]);
3290     NEditFree(LMDialog.languageModeList);
3291 }
3292 
lmOkCB(Widget w,XtPointer clientData,XtPointer callData)3293 static void lmOkCB(Widget w, XtPointer clientData, XtPointer callData)
3294 {
3295     if (!updateLMList())
3296     	return;
3297 
3298     /* pop down and destroy the dialog */
3299     XtDestroyWidget(LMDialog.shell);
3300     LMDialog.shell = NULL;
3301 }
3302 
lmApplyCB(Widget w,XtPointer clientData,XtPointer callData)3303 static void lmApplyCB(Widget w, XtPointer clientData, XtPointer callData)
3304 {
3305     updateLMList();
3306 }
3307 
lmCloseCB(Widget w,XtPointer clientData,XtPointer callData)3308 static void lmCloseCB(Widget w, XtPointer clientData, XtPointer callData)
3309 {
3310     /* pop down and destroy the dialog */
3311     XtDestroyWidget(LMDialog.shell);
3312     LMDialog.shell = NULL;
3313 }
3314 
lmDeleteConfirmCB(int itemIndex,void * cbArg)3315 static int lmDeleteConfirmCB(int itemIndex, void *cbArg)
3316 {
3317     int i;
3318 
3319     /* Allow duplicate names to be deleted regardless of dependencies */
3320     for (i=0; i<LMDialog.nLanguageModes; i++)
3321 	if (i != itemIndex && !strcmp(LMDialog.languageModeList[i]->name,
3322 		LMDialog.languageModeList[itemIndex]->name))
3323 	    return True;
3324 
3325     /* don't allow deletion if data will be lost */
3326     if (LMHasHighlightPatterns(LMDialog.languageModeList[itemIndex]->name))
3327     {
3328         DialogF(DF_WARN, LMDialog.shell, 1, "Patterns exist",
3329                 "This language mode has syntax highlighting\n"
3330                 "patterns defined.  Please delete the patterns\n"
3331                 "first, in Preferences -> Default Settings ->\n"
3332                 "Syntax Highlighting, before proceeding here.", "OK");
3333         return False;
3334     }
3335 
3336     /* don't allow deletion if data will be lost */
3337     if (LMHasSmartIndentMacros(LMDialog.languageModeList[itemIndex]->name))
3338     {
3339         DialogF(DF_WARN, LMDialog.shell, 1, "Smart Indent Macros exist",
3340                 "This language mode has smart indent macros\n"
3341                 "defined.  Please delete the macros first,\n"
3342                 "in Preferences -> Default Settings ->\n"
3343                 "Auto Indent -> Program Smart Indent,\n"
3344                 "before proceeding here.", "OK");
3345         return False;
3346     }
3347 
3348     return True;
3349 }
3350 
3351 /*
3352 ** Apply the changes that the user has made in the language modes dialog to the
3353 ** stored language mode information for this NEdit session (the data array
3354 ** LanguageModes)
3355 */
updateLMList(void)3356 static int updateLMList(void)
3357 {
3358     WindowInfo *window;
3359     int oldLanguageMode;
3360     char *oldModeName, *newDelimiters;
3361     int i, j;
3362 
3363     /* Get the current contents of the dialog fields */
3364     if (!UpdateManagedList(LMDialog.managedListW, True))
3365     	return False;
3366 
3367     /* Fix up language mode indices in all open windows (which may change
3368        if the currently selected mode is deleted or has changed position),
3369        and update word delimiters */
3370     for (window=WindowList; window!=NULL; window=window->next) {
3371 	if (window->languageMode != PLAIN_LANGUAGE_MODE) {
3372             oldLanguageMode = window->languageMode;
3373     	    oldModeName = LanguageModes[window->languageMode]->name;
3374     	    window->languageMode = PLAIN_LANGUAGE_MODE;
3375     	    for (i=0; i<LMDialog.nLanguageModes; i++) {
3376     		if (!strcmp(oldModeName, LMDialog.languageModeList[i]->name)) {
3377     	    	    newDelimiters = LMDialog.languageModeList[i]->delimiters;
3378     	    	    if (newDelimiters == NULL)
3379     	    	    	newDelimiters = GetPrefDelimiters();
3380     	    	    XtVaSetValues(window->textArea, textNwordDelimiters,
3381     	    	    	    newDelimiters, NULL);
3382     	    	    for (j=0; j<window->nPanes; j++)
3383     	    	    	XtVaSetValues(window->textPanes[j],
3384     	    	    	    	textNwordDelimiters, newDelimiters, NULL);
3385                     /* don't forget to adapt the LM stored within the user menu cache */
3386                     if (window->userMenuCache->umcLanguageMode == oldLanguageMode)
3387                         window->userMenuCache->umcLanguageMode = i;
3388                     if (window->userBGMenuCache.ubmcLanguageMode == oldLanguageMode)
3389                         window->userBGMenuCache.ubmcLanguageMode = i;
3390                     /* update the language mode of this window (document) */
3391     	    	    window->languageMode = i;
3392     	    	    break;
3393     		}
3394     	    }
3395 	}
3396     }
3397 
3398     /* If there were any name changes, re-name dependent highlight patterns
3399        and smart-indent macros and fix up the weird rename-format names */
3400     for (i=0; i<LMDialog.nLanguageModes; i++) {
3401     	if (strchr(LMDialog.languageModeList[i]->name, ':') != NULL) {
3402     	    char *newName = strrchr(LMDialog.languageModeList[i]->name, ':')+1;
3403     	    *strchr(LMDialog.languageModeList[i]->name, ':') = '\0';
3404     	    RenameHighlightPattern(LMDialog.languageModeList[i]->name, newName);
3405     	    RenameSmartIndentMacros(LMDialog.languageModeList[i]->name, newName);
3406     	    memmove(LMDialog.languageModeList[i]->name, newName,
3407     	    	    strlen(newName) + 1);
3408     	    ChangeManagedListData(LMDialog.managedListW);
3409     	}
3410     }
3411 
3412     /* Replace the old language mode list with the new one from the dialog */
3413     for (i=0; i<NLanguageModes; i++)
3414     	freeLanguageModeRec(LanguageModes[i]);
3415     for (i=0; i<LMDialog.nLanguageModes; i++)
3416     	LanguageModes[i] = copyLanguageModeRec(LMDialog.languageModeList[i]);
3417     NLanguageModes = LMDialog.nLanguageModes;
3418 
3419     /* Update user menu info to update language mode dependencies of
3420        user menu items */
3421     UpdateUserMenuInfo();
3422 
3423     /* Update the menus in the window menu bars and load any needed
3424         calltips files */
3425     for (window=WindowList; window!=NULL; window=window->next) {
3426     	updateLanguageModeSubmenu(window);
3427         if (window->languageMode != PLAIN_LANGUAGE_MODE &&
3428                 LanguageModes[window->languageMode]->defTipsFile != NULL)
3429             AddTagsFile(LanguageModes[window->languageMode]->defTipsFile, TIP);
3430         /* cache user menus: Rebuild all user menus of this window */
3431         RebuildAllMenus(window);
3432     }
3433 
3434     /* If a syntax highlighting dialog is up, update its menu */
3435     UpdateLanguageModeMenu();
3436     /* The same for the smart indent macro dialog */
3437     UpdateLangModeMenuSmartIndent();
3438     /* Note that preferences have been changed */
3439     MarkPrefsChanged();
3440 
3441     return True;
3442 }
3443 
lmGetDisplayedCB(void * oldItem,int explicitRequest,int * abort,void * cbArg)3444 static void *lmGetDisplayedCB(void *oldItem, int explicitRequest, int *abort,
3445     	void *cbArg)
3446 {
3447     languageModeRec *lm, *oldLM = (languageModeRec *)oldItem;
3448     char *tempName;
3449     int i, nCopies, oldLen;
3450 
3451     /* If the dialog is currently displaying the "new" entry and the
3452        fields are empty, that's just fine */
3453     if (oldItem == NULL && lmDialogEmpty())
3454     	return NULL;
3455 
3456     /* Read the data the user has entered in the dialog fields */
3457     lm = readLMDialogFields(True);
3458 
3459     /* If there was a name change of a non-duplicate language mode, modify the
3460        name to the weird format of: ":old name:new name".  This signals that a
3461        name change is necessary in lm dependent data such as highlight
3462        patterns.  Duplicate language modes may be re-named at will, since no
3463        data will be lost due to the name change. */
3464     if (lm != NULL && oldLM != NULL && strcmp(oldLM->name, lm->name)) {
3465     	nCopies = 0;
3466 	for (i=0; i<LMDialog.nLanguageModes; i++)
3467 	    if (!strcmp(oldLM->name, LMDialog.languageModeList[i]->name))
3468 		nCopies++;
3469 	if (nCopies <= 1) {
3470     	    oldLen = strchr(oldLM->name, ':') == NULL ? strlen(oldLM->name) :
3471     	    	    strchr(oldLM->name, ':') - oldLM->name;
3472     	    tempName = (char*)NEditMalloc(oldLen + strlen(lm->name) + 2);
3473     	    strncpy(tempName, oldLM->name, oldLen);
3474     	    sprintf(&tempName[oldLen], ":%s", lm->name);
3475     	    NEditFree(lm->name);
3476     	    lm->name = tempName;
3477 	}
3478     }
3479 
3480     /* If there are no problems reading the data, just return it */
3481     if (lm != NULL)
3482     	return (void *)lm;
3483 
3484     /* If there are problems, and the user didn't ask for the fields to be
3485        read, give more warning */
3486     if (!explicitRequest)
3487     {
3488         if (DialogF(DF_WARN, LMDialog.shell, 2, "Discard Language Mode",
3489                 "Discard incomplete entry\nfor current language mode?", "Keep",
3490                 "Discard") == 2)
3491         {
3492             return oldItem == NULL
3493                     ? NULL
3494                     : (void *)copyLanguageModeRec((languageModeRec *)oldItem);
3495         }
3496     }
3497 
3498     /* Do readLMDialogFields again without "silent" mode to display warning */
3499     lm = readLMDialogFields(False);
3500     *abort = True;
3501     return NULL;
3502 }
3503 
lmSetDisplayedCB(void * item,void * cbArg)3504 static void lmSetDisplayedCB(void *item, void *cbArg)
3505 {
3506     languageModeRec *lm = (languageModeRec *)item;
3507     char *extStr;
3508 
3509     if (item == NULL) {
3510     	XmTextSetString(LMDialog.nameW, "");
3511     	XmTextSetString(LMDialog.extW, "");
3512     	XmTextSetString(LMDialog.recogW, "");
3513         XmTextSetString(LMDialog.defTipsW, "");
3514     	XmTextSetString(LMDialog.delimitW, "");
3515     	XmTextSetString(LMDialog.tabW, "");
3516     	XmTextSetString(LMDialog.emTabW, "");
3517     	RadioButtonChangeState(LMDialog.defaultIndentW, True, True);
3518     	RadioButtonChangeState(LMDialog.defaultWrapW, True, True);
3519     } else {
3520     	XmTextSetString(LMDialog.nameW, strchr(lm->name, ':') == NULL ?
3521     	    	lm->name : strchr(lm->name, ':')+1);
3522     	extStr = createExtString(lm->extensions, lm->nExtensions);
3523     	XmTextSetString(LMDialog.extW, extStr);
3524     	NEditFree(extStr);
3525     	XmTextSetString(LMDialog.recogW, lm->recognitionExpr);
3526         XmTextSetString(LMDialog.defTipsW, lm->defTipsFile);
3527     	XmTextSetString(LMDialog.delimitW, lm->delimiters);
3528     	if (lm->tabDist == DEFAULT_TAB_DIST)
3529     	    XmTextSetString(LMDialog.tabW, "");
3530     	else
3531     	    SetIntText(LMDialog.tabW, lm->tabDist);
3532     	if (lm->emTabDist == DEFAULT_EM_TAB_DIST)
3533     	    XmTextSetString(LMDialog.emTabW, "");
3534     	else
3535     	    SetIntText(LMDialog.emTabW, lm->emTabDist);
3536     	RadioButtonChangeState(LMDialog.defaultIndentW,
3537     	    	lm->indentStyle == DEFAULT_INDENT, False);
3538     	RadioButtonChangeState(LMDialog.noIndentW,
3539     	    	lm->indentStyle == NO_AUTO_INDENT, False);
3540     	RadioButtonChangeState(LMDialog.autoIndentW,
3541     	    	lm->indentStyle == AUTO_INDENT, False);
3542     	RadioButtonChangeState(LMDialog.smartIndentW,
3543     	    	lm->indentStyle == SMART_INDENT, False);
3544     	RadioButtonChangeState(LMDialog.defaultWrapW,
3545     	    	lm->wrapStyle == DEFAULT_WRAP, False);
3546     	RadioButtonChangeState(LMDialog.noWrapW,
3547     	    	lm->wrapStyle == NO_WRAP, False);
3548     	RadioButtonChangeState(LMDialog.newlineWrapW,
3549     	    	lm->wrapStyle == NEWLINE_WRAP, False);
3550     	RadioButtonChangeState(LMDialog.contWrapW,
3551     	    	lm->wrapStyle == CONTINUOUS_WRAP, False);
3552     }
3553 }
3554 
lmFreeItemCB(void * item)3555 static void lmFreeItemCB(void *item)
3556 {
3557     freeLanguageModeRec((languageModeRec *)item);
3558 }
3559 
freeLanguageModeRec(languageModeRec * lm)3560 static void freeLanguageModeRec(languageModeRec *lm)
3561 {
3562     int i;
3563 
3564     NEditFree(lm->name);
3565     NEditFree(lm->recognitionExpr);
3566     NEditFree(lm->defTipsFile);
3567     NEditFree(lm->delimiters);
3568     for (i=0; i<lm->nExtensions; i++)
3569     	NEditFree(lm->extensions[i]);
3570     NEditFree(lm->extensions);
3571     NEditFree(lm);
3572 }
3573 
3574 /*
3575 ** Copy a languageModeRec data structure and all of the allocated data it contains
3576 */
copyLanguageModeRec(languageModeRec * lm)3577 static languageModeRec *copyLanguageModeRec(languageModeRec *lm)
3578 {
3579     languageModeRec *newLM;
3580     int i;
3581 
3582     newLM = (languageModeRec *)NEditMalloc(sizeof(languageModeRec));
3583     newLM->name = NEditStrdup(lm->name);
3584     newLM->nExtensions = lm->nExtensions;
3585     newLM->extensions = (char **)NEditMalloc(sizeof(char *) * lm->nExtensions);
3586     for (i=0; i<lm->nExtensions; i++) {
3587     	newLM->extensions[i] = NEditStrdup(lm->extensions[i]);
3588     }
3589     if (lm->recognitionExpr == NULL)
3590     	newLM->recognitionExpr = NULL;
3591     else {
3592 	newLM->recognitionExpr = NEditStrdup(lm->recognitionExpr);
3593     }
3594     if (lm->defTipsFile == NULL)
3595     	newLM->defTipsFile = NULL;
3596     else {
3597 	newLM->defTipsFile = NEditStrdup(lm->defTipsFile);
3598     }
3599     if (lm->delimiters == NULL)
3600     	newLM->delimiters = NULL;
3601     else {
3602 	newLM->delimiters = NEditStrdup(lm->delimiters);
3603     }
3604     newLM->wrapStyle = lm->wrapStyle;
3605     newLM->indentStyle = lm->indentStyle;
3606     newLM->tabDist = lm->tabDist;
3607     newLM->emTabDist = lm->emTabDist;
3608     return newLM;
3609 }
3610 
3611 /*
3612 ** Read the fields in the language modes dialog and create a languageModeRec data
3613 ** structure reflecting the current state of the selected language mode in the dialog.
3614 ** If any of the information is incorrect or missing, display a warning dialog and
3615 ** return NULL.  Passing "silent" as True, suppresses the warning dialogs.
3616 */
readLMDialogFields(int silent)3617 static languageModeRec *readLMDialogFields(int silent)
3618 {
3619     languageModeRec *lm;
3620     regexp *compiledRE;
3621     char *compileMsg, *extStr, *extPtr;
3622 
3623     /* Allocate a language mode structure to return, set unread fields to
3624        empty so everything can be freed on errors by freeLanguageModeRec */
3625     lm = (languageModeRec *)NEditMalloc(sizeof(languageModeRec));
3626     lm->nExtensions = 0;
3627     lm->recognitionExpr = NULL;
3628     lm->defTipsFile = NULL;
3629     lm->delimiters = NULL;
3630 
3631     /* read the name field */
3632     lm->name = ReadSymbolicFieldTextWidget(LMDialog.nameW,
3633     	    "language mode name", silent);
3634     if (lm->name == NULL) {
3635     	NEditFree(lm);
3636     	return NULL;
3637     }
3638 
3639     if (*lm->name == '\0')
3640     {
3641         if (!silent)
3642         {
3643             DialogF(DF_WARN, LMDialog.shell, 1, "Language Mode Name",
3644                     "Please specify a name\nfor the language mode", "OK");
3645             XmProcessTraversal(LMDialog.nameW, XmTRAVERSE_CURRENT);
3646         }
3647         freeLanguageModeRec(lm);
3648         return NULL;
3649     }
3650 
3651     /* read the extension list field */
3652     extStr = extPtr = XmTextGetString(LMDialog.extW);
3653     lm->extensions = readExtensionList(&extPtr, &lm->nExtensions);
3654     NEditFree(extStr);
3655 
3656     /* read recognition expression */
3657     lm->recognitionExpr = XmTextGetString(LMDialog.recogW);
3658     if (*lm->recognitionExpr == '\0') {
3659     	NEditFree(lm->recognitionExpr);
3660     	lm->recognitionExpr = NULL;
3661     } else
3662     {
3663         compiledRE = CompileRE(lm->recognitionExpr, &compileMsg, REDFLT_STANDARD);
3664 
3665         if (compiledRE == NULL)
3666         {
3667             if (!silent)
3668             {
3669                 DialogF(DF_WARN, LMDialog.shell, 1, "Regex",
3670                         "Recognition expression:\n%s", "OK", compileMsg);
3671                 XmProcessTraversal(LMDialog.recogW, XmTRAVERSE_CURRENT);
3672             }
3673             NEditFree(compiledRE);
3674             freeLanguageModeRec(lm);
3675             return NULL;
3676         }
3677 
3678         NEditFree(compiledRE);
3679     }
3680 
3681     /* Read the default calltips file for the language mode */
3682     lm->defTipsFile = XmTextGetString(LMDialog.defTipsW);
3683     if (*lm->defTipsFile == '\0') {
3684         /* Empty string */
3685     	NEditFree(lm->defTipsFile);
3686     	lm->defTipsFile = NULL;
3687     } else {
3688         /* Ensure that AddTagsFile will work */
3689         if (AddTagsFile(lm->defTipsFile, TIP) == FALSE) {
3690             if (!silent)
3691             {
3692                 DialogF(DF_WARN, LMDialog.shell, 1, "Error reading Calltips",
3693                         "Can't read default calltips file(s):\n  \"%s\"\n",
3694                         "OK", lm->defTipsFile);
3695                 XmProcessTraversal(LMDialog.recogW, XmTRAVERSE_CURRENT);
3696             }
3697             freeLanguageModeRec(lm);
3698             return NULL;
3699         } else
3700             if (DeleteTagsFile(lm->defTipsFile, TIP, False) == FALSE)
3701                 fprintf(stderr, "nedit: Internal error: Trouble deleting "
3702                         "calltips file(s):\n  \"%s\"\n", lm->defTipsFile);
3703     }
3704 
3705     /* read tab spacing field */
3706     if (TextWidgetIsBlank(LMDialog.tabW))
3707     	lm->tabDist = DEFAULT_TAB_DIST;
3708     else {
3709     	if (GetIntTextWarn(LMDialog.tabW, &lm->tabDist, "tab spacing", False)
3710     	    	!= TEXT_READ_OK) {
3711    	    freeLanguageModeRec(lm);
3712     	    return NULL;
3713 	}
3714 
3715         if (lm->tabDist <= 0 || lm->tabDist > 100)
3716         {
3717             if (!silent)
3718             {
3719                 DialogF(DF_WARN, LMDialog.shell, 1, "Invalid Tab Spacing",
3720                         "Invalid tab spacing: %d", "OK", lm->tabDist);
3721                 XmProcessTraversal(LMDialog.tabW, XmTRAVERSE_CURRENT);
3722             }
3723             freeLanguageModeRec(lm);
3724             return NULL;
3725         }
3726     }
3727 
3728     /* read emulated tab field */
3729     if (TextWidgetIsBlank(LMDialog.emTabW))
3730     {
3731         lm->emTabDist = DEFAULT_EM_TAB_DIST;
3732     } else
3733     {
3734         if (GetIntTextWarn(LMDialog.emTabW, &lm->emTabDist,
3735                 "emulated tab spacing", False) != TEXT_READ_OK)
3736         {
3737             freeLanguageModeRec(lm);
3738             return NULL;
3739         }
3740 
3741         if (lm->emTabDist < 0 || lm->emTabDist > 100)
3742         {
3743             if (!silent)
3744             {
3745                 DialogF(DF_WARN, LMDialog.shell, 1, "Invalid Tab Spacing",
3746                         "Invalid emulated tab spacing: %d", "OK",
3747                         lm->emTabDist);
3748                 XmProcessTraversal(LMDialog.emTabW, XmTRAVERSE_CURRENT);
3749             }
3750             freeLanguageModeRec(lm);
3751             return NULL;
3752         }
3753     }
3754 
3755     /* read delimiters string */
3756     lm->delimiters = XmTextGetString(LMDialog.delimitW);
3757     if (*lm->delimiters == '\0') {
3758     	NEditFree(lm->delimiters);
3759     	lm->delimiters = NULL;
3760     }
3761 
3762     /* read indent style */
3763     if (XmToggleButtonGetState(LMDialog.noIndentW))
3764     	 lm->indentStyle = NO_AUTO_INDENT;
3765     else if (XmToggleButtonGetState(LMDialog.autoIndentW))
3766     	 lm->indentStyle = AUTO_INDENT;
3767     else if (XmToggleButtonGetState(LMDialog.smartIndentW))
3768     	 lm->indentStyle = SMART_INDENT;
3769     else
3770     	 lm->indentStyle = DEFAULT_INDENT;
3771 
3772     /* read wrap style */
3773     if (XmToggleButtonGetState(LMDialog.noWrapW))
3774     	 lm->wrapStyle = NO_WRAP;
3775     else if (XmToggleButtonGetState(LMDialog.newlineWrapW))
3776     	 lm->wrapStyle = NEWLINE_WRAP;
3777     else if (XmToggleButtonGetState(LMDialog.contWrapW))
3778     	 lm->wrapStyle = CONTINUOUS_WRAP;
3779     else
3780     	 lm->wrapStyle = DEFAULT_WRAP;
3781 
3782     return lm;
3783 }
3784 
3785 /*
3786 ** Return True if the language mode dialog fields are blank (unchanged from the "New"
3787 ** language mode state).
3788 */
lmDialogEmpty(void)3789 static int lmDialogEmpty(void)
3790 {
3791     return TextWidgetIsBlank(LMDialog.nameW) &&
3792  	    TextWidgetIsBlank(LMDialog.extW) &&
3793 	    TextWidgetIsBlank(LMDialog.recogW) &&
3794 	    TextWidgetIsBlank(LMDialog.delimitW) &&
3795 	    TextWidgetIsBlank(LMDialog.tabW) &&
3796 	    TextWidgetIsBlank(LMDialog.emTabW) &&
3797 	    XmToggleButtonGetState(LMDialog.defaultIndentW) &&
3798 	    XmToggleButtonGetState(LMDialog.defaultWrapW);
3799 }
3800 
3801 /*
3802 ** Present a dialog for changing fonts (primary, and for highlighting).
3803 */
ChooseFonts(WindowInfo * window,int forWindow)3804 void ChooseFonts(WindowInfo *window, int forWindow)
3805 {
3806 #define MARGIN_SPACING 10
3807 #define BTN_TEXT_OFFSET 3
3808     Widget form, primaryLbl, primaryBtn, italicLbl, italicBtn;
3809     Widget boldLbl, boldBtn, boldItalicLbl, boldItalicBtn;
3810     Widget primaryFrame, primaryForm, highlightFrame, highlightForm;
3811     Widget okBtn, applyBtn, cancelBtn;
3812     fontDialog *fd;
3813     XmString s1;
3814     int ac;
3815     Arg args[20];
3816 
3817     /* if the dialog is already displayed, just pop it to the top and return */
3818     if (window->fontDialog != NULL) {
3819     	RaiseDialogWindow(((fontDialog *)window->fontDialog)->shell);
3820     	return;
3821     }
3822 
3823     /* Create a structure for keeping track of dialog state */
3824     fd = (fontDialog *)NEditMalloc(sizeof(fontDialog));
3825     fd->window = window;
3826     fd->forWindow = forWindow;
3827     window->fontDialog = (void*)fd;
3828 
3829     /* Create a form widget in a dialog shell */
3830     ac = 0;
3831     XtSetArg(args[ac], XmNautoUnmanage, False); ac++;
3832     XtSetArg(args[ac], XmNresizePolicy, XmRESIZE_NONE); ac++;
3833     form = CreateFormDialog(window->shell, "choose Fonts", args, ac);
3834     XtVaSetValues(form, XmNshadowThickness, 0, NULL);
3835     fd->shell = XtParent(form);
3836     XtVaSetValues(fd->shell, XmNtitle, "Text Fonts", NULL);
3837     AddMotifCloseCallback(XtParent(form), fontCancelCB, fd);
3838     XtAddCallback(form, XmNdestroyCallback, fontDestroyCB, fd);
3839 
3840     primaryFrame = XtVaCreateManagedWidget("primaryFrame", xmFrameWidgetClass,
3841     	    form, XmNmarginHeight, 3,
3842 	    XmNtopAttachment, XmATTACH_POSITION,
3843 	    XmNtopPosition, 2,
3844 	    XmNleftAttachment, XmATTACH_POSITION,
3845 	    XmNleftPosition, 1,
3846 	    XmNrightAttachment, XmATTACH_POSITION,
3847 	    XmNrightPosition, 99, NULL);
3848     primaryForm = XtVaCreateManagedWidget("primaryForm", xmFormWidgetClass,
3849 	    primaryFrame, NULL);
3850     primaryLbl = XtVaCreateManagedWidget("primaryFont", xmLabelGadgetClass,
3851     	    primaryFrame,
3852     	    XmNlabelString, s1=XmStringCreateSimple("Primary Font"),
3853     	    XmNmnemonic, 'P',
3854 	    XmNchildType, XmFRAME_TITLE_CHILD,
3855 	    XmNchildHorizontalAlignment, XmALIGNMENT_CENTER, NULL);
3856     XmStringFree(s1);
3857 
3858     primaryBtn = XtVaCreateManagedWidget("primaryBtn",
3859     	    xmPushButtonWidgetClass, primaryForm,
3860     	    XmNlabelString, s1=XmStringCreateSimple("Browse..."),
3861     	    XmNmnemonic, 'r',
3862 	    XmNtopAttachment, XmATTACH_POSITION,
3863 	    XmNtopPosition, 2,
3864 	    XmNtopOffset, BTN_TEXT_OFFSET,
3865 	    XmNleftAttachment, XmATTACH_POSITION,
3866 	    XmNleftPosition, 1, NULL);
3867     XmStringFree(s1);
3868     XtAddCallback(primaryBtn, XmNactivateCallback, primaryBrowseCB, fd);
3869 
3870     fd->primaryW = XtVaCreateManagedWidget("primary", xmTextWidgetClass,
3871     	    primaryForm,
3872     	    XmNcolumns, 70,
3873     	    XmNmaxLength, MAX_FONT_LEN,
3874 	    XmNleftAttachment, XmATTACH_WIDGET,
3875 	    XmNleftWidget, primaryBtn,
3876 	    XmNtopAttachment, XmATTACH_POSITION,
3877 	    XmNtopPosition, 2,
3878 	    XmNrightAttachment, XmATTACH_POSITION,
3879 	    XmNrightPosition, 99, NULL);
3880     RemapDeleteKey(fd->primaryW);
3881     XtAddCallback(fd->primaryW, XmNvalueChangedCallback,
3882     	    primaryModifiedCB, fd);
3883     XtVaSetValues(primaryLbl, XmNuserData, fd->primaryW, NULL);
3884 
3885     highlightFrame = XtVaCreateManagedWidget("highlightFrame",
3886     	    xmFrameWidgetClass, form,
3887 	    XmNmarginHeight, 3,
3888 	    XmNnavigationType, XmTAB_GROUP,
3889 	    XmNtopAttachment, XmATTACH_WIDGET,
3890 	    XmNtopWidget, primaryFrame,
3891 	    XmNtopOffset, 20,
3892 	    XmNleftAttachment, XmATTACH_POSITION,
3893 	    XmNleftPosition, 1,
3894 	    XmNrightAttachment, XmATTACH_POSITION,
3895 	    XmNrightPosition, 99, NULL);
3896     highlightForm = XtVaCreateManagedWidget("highlightForm", xmFormWidgetClass,
3897     	    highlightFrame, NULL);
3898     XtVaCreateManagedWidget("highlightFonts", xmLabelGadgetClass,
3899     	    highlightFrame,
3900     	    XmNlabelString,
3901     	    	s1=XmStringCreateSimple("Fonts for Syntax Highlighting"),
3902 	    XmNchildType, XmFRAME_TITLE_CHILD,
3903 	    XmNchildHorizontalAlignment, XmALIGNMENT_CENTER, NULL);
3904     XmStringFree(s1);
3905 
3906     fd->fillW = XtVaCreateManagedWidget("fillBtn",
3907     	    xmPushButtonWidgetClass, highlightForm,
3908     	    XmNlabelString,
3909     	    	s1=XmStringCreateSimple("Fill Highlight Fonts from Primary"),
3910     	    XmNmnemonic, 'F',
3911     	    XmNtopAttachment, XmATTACH_POSITION,
3912 	    XmNtopPosition, 2,
3913 	    XmNtopOffset, BTN_TEXT_OFFSET,
3914 	    XmNleftAttachment, XmATTACH_POSITION,
3915 	    XmNleftPosition, 1, NULL);
3916     XmStringFree(s1);
3917     XtAddCallback(fd->fillW, XmNactivateCallback, fillFromPrimaryCB, fd);
3918 
3919     italicLbl = XtVaCreateManagedWidget("italicLbl", xmLabelGadgetClass,
3920     	    highlightForm,
3921     	    XmNlabelString, s1=XmStringCreateSimple("Italic Font"),
3922     	    XmNmnemonic, 'I',
3923     	    XmNalignment, XmALIGNMENT_BEGINNING,
3924 	    XmNtopAttachment, XmATTACH_WIDGET,
3925 	    XmNtopWidget, fd->fillW,
3926 	    XmNtopOffset, MARGIN_SPACING,
3927 	    XmNleftAttachment, XmATTACH_POSITION,
3928 	    XmNleftPosition, 1, NULL);
3929     XmStringFree(s1);
3930 
3931     fd->italicErrW = XtVaCreateManagedWidget("italicErrLbl",
3932     	    xmLabelGadgetClass, highlightForm,
3933     	    XmNlabelString, s1=XmStringCreateSimple(
3934     	    	"(vvv  spacing is inconsistent with primary font  vvv)"),
3935     	    XmNalignment, XmALIGNMENT_END,
3936 	    XmNtopAttachment, XmATTACH_WIDGET,
3937 	    XmNtopWidget, fd->fillW,
3938 	    XmNtopOffset, MARGIN_SPACING,
3939 	    XmNleftAttachment, XmATTACH_WIDGET,
3940 	    XmNleftWidget, italicLbl,
3941 	    XmNrightAttachment, XmATTACH_POSITION,
3942 	    XmNrightPosition, 99, NULL);
3943     XmStringFree(s1);
3944 
3945     italicBtn = XtVaCreateManagedWidget("italicBtn",
3946     	    xmPushButtonWidgetClass, highlightForm,
3947     	    XmNlabelString, s1=XmStringCreateSimple("Browse..."),
3948     	    XmNmnemonic, 'o',
3949     	    XmNtopAttachment, XmATTACH_WIDGET,
3950 	    XmNtopWidget, italicLbl,
3951 	    XmNtopOffset, BTN_TEXT_OFFSET,
3952 	    XmNleftAttachment, XmATTACH_POSITION,
3953 	    XmNleftPosition, 1, NULL);
3954     XmStringFree(s1);
3955     XtAddCallback(italicBtn, XmNactivateCallback, italicBrowseCB, fd);
3956 
3957     fd->italicW = XtVaCreateManagedWidget("italic", xmTextWidgetClass,
3958     	    highlightForm,
3959     	    XmNmaxLength, MAX_FONT_LEN,
3960 	    XmNleftAttachment, XmATTACH_WIDGET,
3961 	    XmNleftWidget, italicBtn,
3962 	    XmNtopAttachment, XmATTACH_WIDGET,
3963 	    XmNtopWidget, italicLbl,
3964 	    XmNrightAttachment, XmATTACH_POSITION,
3965 	    XmNrightPosition, 99, NULL);
3966     RemapDeleteKey(fd->italicW);
3967     XtAddCallback(fd->italicW, XmNvalueChangedCallback,
3968     	    italicModifiedCB, fd);
3969     XtVaSetValues(italicLbl, XmNuserData, fd->italicW, NULL);
3970 
3971     boldLbl = XtVaCreateManagedWidget("boldLbl", xmLabelGadgetClass,
3972     	    highlightForm,
3973     	    XmNlabelString, s1=XmStringCreateSimple("Bold Font"),
3974     	    XmNmnemonic, 'B',
3975     	    XmNalignment, XmALIGNMENT_BEGINNING,
3976 	    XmNtopAttachment, XmATTACH_WIDGET,
3977 	    XmNtopWidget, italicBtn,
3978 	    XmNtopOffset, MARGIN_SPACING,
3979 	    XmNleftAttachment, XmATTACH_POSITION,
3980 	    XmNleftPosition, 1, NULL);
3981     XmStringFree(s1);
3982 
3983     fd->boldErrW = XtVaCreateManagedWidget("boldErrLbl",
3984     	    xmLabelGadgetClass, highlightForm,
3985     	    XmNlabelString, s1=XmStringCreateSimple(""),
3986     	    XmNalignment, XmALIGNMENT_END,
3987 	    XmNtopAttachment, XmATTACH_WIDGET,
3988 	    XmNtopWidget, italicBtn,
3989 	    XmNtopOffset, MARGIN_SPACING,
3990 	    XmNleftAttachment, XmATTACH_WIDGET,
3991 	    XmNleftWidget, boldLbl,
3992 	    XmNrightAttachment, XmATTACH_POSITION,
3993 	    XmNrightPosition, 99, NULL);
3994     XmStringFree(s1);
3995 
3996     boldBtn = XtVaCreateManagedWidget("boldBtn",
3997     	    xmPushButtonWidgetClass, highlightForm,
3998     	    XmNlabelString, s1=XmStringCreateSimple("Browse..."),
3999     	    XmNmnemonic, 'w',
4000     	    XmNtopAttachment, XmATTACH_WIDGET,
4001 	    XmNtopWidget, boldLbl,
4002 	    XmNtopOffset, BTN_TEXT_OFFSET,
4003 	    XmNleftAttachment, XmATTACH_POSITION,
4004 	    XmNleftPosition, 1, NULL);
4005     XmStringFree(s1);
4006     XtAddCallback(boldBtn, XmNactivateCallback, boldBrowseCB, fd);
4007 
4008     fd->boldW = XtVaCreateManagedWidget("bold", xmTextWidgetClass,
4009     	    highlightForm,
4010     	    XmNmaxLength, MAX_FONT_LEN,
4011 	    XmNleftAttachment, XmATTACH_WIDGET,
4012 	    XmNleftWidget, boldBtn,
4013 	    XmNtopAttachment, XmATTACH_WIDGET,
4014 	    XmNtopWidget, boldLbl,
4015 	    XmNrightAttachment, XmATTACH_POSITION,
4016 	    XmNrightPosition, 99, NULL);
4017     RemapDeleteKey(fd->boldW);
4018     XtAddCallback(fd->boldW, XmNvalueChangedCallback,
4019     	    boldModifiedCB, fd);
4020     XtVaSetValues(boldLbl, XmNuserData, fd->boldW, NULL);
4021 
4022     boldItalicLbl = XtVaCreateManagedWidget("boldItalicLbl", xmLabelGadgetClass,
4023     	    highlightForm,
4024     	    XmNlabelString, s1=XmStringCreateSimple("Bold Italic Font"),
4025     	    XmNmnemonic, 'l',
4026     	    XmNalignment, XmALIGNMENT_BEGINNING,
4027 	    XmNtopAttachment, XmATTACH_WIDGET,
4028 	    XmNtopWidget, boldBtn,
4029 	    XmNtopOffset, MARGIN_SPACING,
4030 	    XmNleftAttachment, XmATTACH_POSITION,
4031 	    XmNleftPosition, 1, NULL);
4032     XmStringFree(s1);
4033 
4034     fd->boldItalicErrW = XtVaCreateManagedWidget("boldItalicErrLbl",
4035     	    xmLabelGadgetClass, highlightForm,
4036     	    XmNlabelString, s1=XmStringCreateSimple(""),
4037     	    XmNalignment, XmALIGNMENT_END,
4038 	    XmNtopAttachment, XmATTACH_WIDGET,
4039 	    XmNtopWidget, boldBtn,
4040 	    XmNtopOffset, MARGIN_SPACING,
4041 	    XmNleftAttachment, XmATTACH_WIDGET,
4042 	    XmNleftWidget, boldItalicLbl,
4043 	    XmNrightAttachment, XmATTACH_POSITION,
4044 	    XmNrightPosition, 99, NULL);
4045     XmStringFree(s1);
4046 
4047     boldItalicBtn = XtVaCreateManagedWidget("boldItalicBtn",
4048     	    xmPushButtonWidgetClass, highlightForm,
4049     	    XmNlabelString, s1=XmStringCreateSimple("Browse..."),
4050     	    XmNmnemonic, 's',
4051     	    XmNtopAttachment, XmATTACH_WIDGET,
4052 	    XmNtopWidget, boldItalicLbl,
4053 	    XmNtopOffset, BTN_TEXT_OFFSET,
4054 	    XmNleftAttachment, XmATTACH_POSITION,
4055 	    XmNleftPosition, 1, NULL);
4056     XmStringFree(s1);
4057     XtAddCallback(boldItalicBtn, XmNactivateCallback, boldItalicBrowseCB, fd);
4058 
4059     fd->boldItalicW = XtVaCreateManagedWidget("boldItalic",
4060     	    xmTextWidgetClass, highlightForm,
4061     	    XmNmaxLength, MAX_FONT_LEN,
4062 	    XmNleftAttachment, XmATTACH_WIDGET,
4063 	    XmNleftWidget, boldItalicBtn,
4064 	    XmNtopAttachment, XmATTACH_WIDGET,
4065 	    XmNtopWidget, boldItalicLbl,
4066 	    XmNrightAttachment, XmATTACH_POSITION,
4067 	    XmNrightPosition, 99, NULL);
4068     RemapDeleteKey(fd->boldItalicW);
4069     XtAddCallback(fd->boldItalicW, XmNvalueChangedCallback,
4070     	    boldItalicModifiedCB, fd);
4071     XtVaSetValues(boldItalicLbl, XmNuserData, fd->boldItalicW, NULL);
4072 
4073     okBtn = XtVaCreateManagedWidget("ok", xmPushButtonWidgetClass, form,
4074             XmNlabelString, s1=XmStringCreateSimple("OK"),
4075             XmNmarginWidth, BUTTON_WIDTH_MARGIN,
4076     	    XmNtopAttachment, XmATTACH_WIDGET,
4077 	    XmNtopWidget, highlightFrame,
4078 	    XmNtopOffset, MARGIN_SPACING,
4079     	    XmNleftAttachment, XmATTACH_POSITION,
4080     	    XmNleftPosition, forWindow ? 13 : 26,
4081     	    XmNrightAttachment, XmATTACH_POSITION,
4082     	    XmNrightPosition, forWindow ? 27 : 40, NULL);
4083     XtAddCallback(okBtn, XmNactivateCallback, fontOkCB, fd);
4084     XmStringFree(s1);
4085 
4086     if (forWindow) {
4087 	applyBtn = XtVaCreateManagedWidget("apply",xmPushButtonWidgetClass,form,
4088     		XmNlabelString, s1=XmStringCreateSimple("Apply"),
4089     		XmNmnemonic, 'A',
4090     		XmNtopAttachment, XmATTACH_WIDGET,
4091 		XmNtopWidget, highlightFrame,
4092 		XmNtopOffset, MARGIN_SPACING,
4093     		XmNleftAttachment, XmATTACH_POSITION,
4094     		XmNleftPosition, 43,
4095     		XmNrightAttachment, XmATTACH_POSITION,
4096     		XmNrightPosition, 57, NULL);
4097 	XtAddCallback(applyBtn, XmNactivateCallback, fontApplyCB, fd);
4098 	XmStringFree(s1);
4099     }
4100 
4101     cancelBtn = XtVaCreateManagedWidget("cancel",
4102             xmPushButtonWidgetClass, form,
4103             XmNlabelString,
4104                     s1 = XmStringCreateSimple(forWindow ? "Close" : "Cancel"),
4105     	    XmNtopAttachment, XmATTACH_WIDGET,
4106 	    XmNtopWidget, highlightFrame,
4107 	    XmNtopOffset, MARGIN_SPACING,
4108     	    XmNleftAttachment, XmATTACH_POSITION,
4109     	    XmNleftPosition, forWindow ? 73 : 59,
4110     	    XmNrightAttachment, XmATTACH_POSITION,
4111     	    XmNrightPosition, forWindow ? 87 : 73,
4112             NULL);
4113     XtAddCallback(cancelBtn, XmNactivateCallback, fontCancelCB, fd);
4114     XmStringFree(s1);
4115 
4116     /* Set initial default button */
4117     XtVaSetValues(form, XmNdefaultButton, okBtn, NULL);
4118     XtVaSetValues(form, XmNcancelButton, cancelBtn, NULL);
4119 
4120     /* Set initial values */
4121     if (forWindow) {
4122 	XmTextSetString(fd->primaryW, window->fontName);
4123 	XmTextSetString(fd->boldW, window->boldFontName);
4124 	XmTextSetString(fd->italicW, window->italicFontName);
4125 	XmTextSetString(fd->boldItalicW, window->boldItalicFontName);
4126     } else {
4127     	XmTextSetString(fd->primaryW, GetPrefFontName());
4128 	XmTextSetString(fd->boldW, GetPrefBoldFontName());
4129 	XmTextSetString(fd->italicW, GetPrefItalicFontName());
4130 	XmTextSetString(fd->boldItalicW, GetPrefBoldItalicFontName());
4131     }
4132 
4133     /* Handle mnemonic selection of buttons and focus to dialog */
4134     AddDialogMnemonicHandler(form, FALSE);
4135 
4136     /* put up dialog */
4137     ManageDialogCenteredOnPointer(form);
4138 }
4139 
fillFromPrimaryCB(Widget w,XtPointer clientData,XtPointer callData)4140 static void fillFromPrimaryCB(Widget w, XtPointer clientData,
4141     	XtPointer callData)
4142 {
4143     fontDialog *fd = (fontDialog *)clientData;
4144     char *primaryName, *errMsg;
4145     char modifiedFontName[MAX_FONT_LEN];
4146     char *searchString = "(-[^-]*-[^-]*)-([^-]*)-([^-]*)-(.*)";
4147     char *italicReplaceString = "\\1-\\2-o-\\4";
4148     char *boldReplaceString = "\\1-bold-\\3-\\4";
4149     char *boldItalicReplaceString = "\\1-bold-o-\\4";
4150     regexp *compiledRE;
4151 
4152     /* Match the primary font agains RE pattern for font names.  If it
4153        doesn't match, we can't generate highlight font names, so return */
4154     compiledRE = CompileRE(searchString, &errMsg, REDFLT_STANDARD);
4155     primaryName = XmTextGetString(fd->primaryW);
4156     if (!ExecRE(compiledRE, primaryName, NULL, False, '\0', '\0', NULL, NULL, NULL)) {
4157     	XBell(XtDisplay(fd->shell), 0);
4158     	free(compiledRE);
4159     	NEditFree(primaryName);
4160     	return;
4161     }
4162 
4163     /* Make up names for new fonts based on RE replace patterns */
4164     SubstituteRE(compiledRE, italicReplaceString, modifiedFontName,
4165     	    MAX_FONT_LEN);
4166     XmTextSetString(fd->italicW, modifiedFontName);
4167     SubstituteRE(compiledRE, boldReplaceString, modifiedFontName,
4168     	    MAX_FONT_LEN);
4169     XmTextSetString(fd->boldW, modifiedFontName);
4170     SubstituteRE(compiledRE, boldItalicReplaceString, modifiedFontName,
4171     	    MAX_FONT_LEN);
4172     XmTextSetString(fd->boldItalicW, modifiedFontName);
4173     NEditFree(primaryName);
4174     NEditFree(compiledRE);
4175 }
4176 
primaryModifiedCB(Widget w,XtPointer clientData,XtPointer callData)4177 static void primaryModifiedCB(Widget w, XtPointer clientData,
4178 	XtPointer callData)
4179 {
4180     fontDialog *fd = (fontDialog *)clientData;
4181 
4182     showFontStatus(fd, fd->italicW, fd->italicErrW);
4183     showFontStatus(fd, fd->boldW, fd->boldErrW);
4184     showFontStatus(fd, fd->boldItalicW, fd->boldItalicErrW);
4185 }
italicModifiedCB(Widget w,XtPointer clientData,XtPointer callData)4186 static void italicModifiedCB(Widget w, XtPointer clientData, XtPointer callData)
4187 {
4188     fontDialog *fd = (fontDialog *)clientData;
4189 
4190     showFontStatus(fd, fd->italicW, fd->italicErrW);
4191 }
boldModifiedCB(Widget w,XtPointer clientData,XtPointer callData)4192 static void boldModifiedCB(Widget w, XtPointer clientData, XtPointer callData)
4193 {
4194     fontDialog *fd = (fontDialog *)clientData;
4195 
4196     showFontStatus(fd, fd->boldW, fd->boldErrW);
4197 }
boldItalicModifiedCB(Widget w,XtPointer clientData,XtPointer callData)4198 static void boldItalicModifiedCB(Widget w, XtPointer clientData,
4199     	XtPointer callData)
4200 {
4201     fontDialog *fd = (fontDialog *)clientData;
4202 
4203     showFontStatus(fd, fd->boldItalicW, fd->boldItalicErrW);
4204 }
4205 
primaryBrowseCB(Widget w,XtPointer clientData,XtPointer callData)4206 static void primaryBrowseCB(Widget w, XtPointer clientData, XtPointer callData)
4207 {
4208     fontDialog *fd = (fontDialog *)clientData;
4209 
4210     browseFont(fd->shell, fd->primaryW);
4211 }
italicBrowseCB(Widget w,XtPointer clientData,XtPointer callData)4212 static void italicBrowseCB(Widget w, XtPointer clientData, XtPointer callData)
4213 {
4214     fontDialog *fd = (fontDialog *)clientData;
4215 
4216     browseFont(fd->shell, fd->italicW);
4217 }
boldBrowseCB(Widget w,XtPointer clientData,XtPointer callData)4218 static void boldBrowseCB(Widget w, XtPointer clientData, XtPointer callData)
4219 {
4220     fontDialog *fd = (fontDialog *)clientData;
4221 
4222     browseFont(fd->shell, fd->boldW);
4223 }
boldItalicBrowseCB(Widget w,XtPointer clientData,XtPointer callData)4224 static void boldItalicBrowseCB(Widget w, XtPointer clientData,
4225     	XtPointer callData)
4226 {
4227    fontDialog *fd = (fontDialog *)clientData;
4228 
4229    browseFont(fd->shell, fd->boldItalicW);
4230 }
4231 
fontDestroyCB(Widget w,XtPointer clientData,XtPointer callData)4232 static void fontDestroyCB(Widget w, XtPointer clientData, XtPointer callData)
4233 {
4234     fontDialog *fd = (fontDialog *)clientData;
4235 
4236     fd->window->fontDialog = NULL;
4237     NEditFree(fd);
4238 }
4239 
fontOkCB(Widget w,XtPointer clientData,XtPointer callData)4240 static void fontOkCB(Widget w, XtPointer clientData, XtPointer callData)
4241 {
4242     fontDialog *fd = (fontDialog *)clientData;
4243 
4244     updateFonts(fd);
4245 
4246     /* pop down and destroy the dialog */
4247     XtDestroyWidget(fd->shell);
4248 }
4249 
fontApplyCB(Widget w,XtPointer clientData,XtPointer callData)4250 static void fontApplyCB(Widget w, XtPointer clientData, XtPointer callData)
4251 {
4252     fontDialog *fd = (fontDialog *)clientData;
4253 
4254     updateFonts(fd);
4255 }
4256 
fontCancelCB(Widget w,XtPointer clientData,XtPointer callData)4257 static void fontCancelCB(Widget w, XtPointer clientData, XtPointer callData)
4258 {
4259     fontDialog *fd = (fontDialog *)clientData;
4260 
4261     /* pop down and destroy the dialog */
4262     XtDestroyWidget(fd->shell);
4263 }
4264 
4265 /*
4266 ** Check over a font name in a text field to make sure it agrees with the
4267 ** primary font in height and spacing.
4268 */
checkFontStatus(fontDialog * fd,Widget fontTextFieldW)4269 static int checkFontStatus(fontDialog *fd, Widget fontTextFieldW)
4270 {
4271     char *primaryName, *testName;
4272     XFontStruct *primaryFont, *testFont;
4273     Display *display = XtDisplay(fontTextFieldW);
4274     int primaryWidth, primaryHeight, testWidth, testHeight;
4275 
4276     /* Get width and height of the font to check.  Note the test for empty
4277        name: X11R6 clients freak out X11R5 servers if they ask them to load
4278        an empty font name, and kill the whole application! */
4279     testName = XmTextGetString(fontTextFieldW);
4280     if (testName[0] == '\0') {
4281 	NEditFree(testName);
4282     	return BAD_FONT;
4283     }
4284     testFont = XLoadQueryFont(display, testName);
4285     if (testFont == NULL) {
4286     	NEditFree(testName);
4287     	return BAD_FONT;
4288     }
4289     NEditFree(testName);
4290     testWidth = testFont->min_bounds.width;
4291     testHeight = testFont->ascent + testFont->descent;
4292     XFreeFont(display, testFont);
4293 
4294     /* Get width and height of the primary font */
4295     primaryName = XmTextGetString(fd->primaryW);
4296     if (primaryName[0] == '\0') {
4297 	NEditFree(primaryName);
4298     	return BAD_FONT;
4299     }
4300     primaryFont = XLoadQueryFont(display, primaryName);
4301     if (primaryFont == NULL) {
4302     	NEditFree(primaryName);
4303     	return BAD_PRIMARY;
4304     }
4305     NEditFree(primaryName);
4306     primaryWidth = primaryFont->min_bounds.width;
4307     primaryHeight = primaryFont->ascent + primaryFont->descent;
4308     XFreeFont(display, primaryFont);
4309 
4310     /* Compare font information */
4311     if (testWidth != primaryWidth)
4312     	return BAD_SPACING;
4313     if (testHeight != primaryHeight)
4314     	return BAD_SIZE;
4315     return GOOD_FONT;
4316 }
4317 
4318 /*
4319 ** Update the error label for a font text field to reflect its validity and degree
4320 ** of agreement with the currently selected primary font
4321 */
showFontStatus(fontDialog * fd,Widget fontTextFieldW,Widget errorLabelW)4322 static int showFontStatus(fontDialog *fd, Widget fontTextFieldW,
4323     	Widget errorLabelW)
4324 {
4325     int status;
4326     XmString s;
4327     char *msg;
4328 
4329     status = checkFontStatus(fd, fontTextFieldW);
4330     if (status == BAD_PRIMARY)
4331     	msg = "(font below may not match primary font)";
4332     else if (status == BAD_FONT)
4333     	msg = "(xxx font below is invalid xxx)";
4334     else if (status == BAD_SIZE)
4335     	msg = "(height of font below does not match primary)";
4336     else if (status == BAD_SPACING)
4337     	msg = "(spacing of font below does not match primary)";
4338     else
4339     	msg = "";
4340 
4341     XtVaSetValues(errorLabelW, XmNlabelString, s=XmStringCreateSimple(msg),
4342 	    NULL);
4343     XmStringFree(s);
4344     return status;
4345 }
4346 
4347 /*
4348 ** Put up a font selector panel to set the font name in the text widget "fontTextW"
4349 */
browseFont(Widget parent,Widget fontTextW)4350 static void browseFont(Widget parent, Widget fontTextW)
4351 {
4352     char *origFontName, *newFontName;
4353     Pixel fgPixel, bgPixel;
4354     int dummy;
4355 
4356     origFontName = XmTextGetString(fontTextW);
4357 
4358     /* Get the values from the defaults */
4359     fgPixel = AllocColor(parent, GetPrefColorName(TEXT_FG_COLOR),
4360             &dummy, &dummy, &dummy);
4361     bgPixel = AllocColor(parent, GetPrefColorName(TEXT_BG_COLOR),
4362             &dummy, &dummy, &dummy);
4363 
4364     newFontName = FontSel(parent, PREF_FIXED, origFontName, fgPixel, bgPixel);
4365     NEditFree(origFontName);
4366     if (newFontName == NULL)
4367     	return;
4368     XmTextSetString(fontTextW, newFontName);
4369     NEditFree(newFontName);
4370 }
4371 
4372 /*
4373 ** Accept the changes in the dialog and set the fonts regardless of errors
4374 */
updateFonts(fontDialog * fd)4375 static void updateFonts(fontDialog *fd)
4376 {
4377     char *fontName, *italicName, *boldName, *boldItalicName;
4378 
4379     fontName = XmTextGetString(fd->primaryW);
4380     italicName = XmTextGetString(fd->italicW);
4381     boldName = XmTextGetString(fd->boldW);
4382     boldItalicName = XmTextGetString(fd->boldItalicW);
4383 
4384     if (fd->forWindow) {
4385         char *params[4];
4386         params[0] = fontName;
4387         params[1] = italicName;
4388         params[2] = boldName;
4389         params[3] = boldItalicName;
4390         XtCallActionProc(fd->window->textArea, "set_fonts", NULL, params, 4);
4391 /*
4392     	SetFonts(fd->window, fontName, italicName, boldName, boldItalicName);
4393 */
4394     }
4395     else {
4396     	SetPrefFont(fontName);
4397     	SetPrefItalicFont(italicName);
4398     	SetPrefBoldFont(boldName);
4399     	SetPrefBoldItalicFont(boldItalicName);
4400     }
4401     NEditFree(fontName);
4402     NEditFree(italicName);
4403     NEditFree(boldName);
4404     NEditFree(boldItalicName);
4405 }
4406 
4407 /*
4408 ** Change the language mode to the one indexed by "mode", reseting word
4409 ** delimiters, syntax highlighting and other mode specific parameters
4410 */
reapplyLanguageMode(WindowInfo * window,int mode,int forceDefaults)4411 static void reapplyLanguageMode(WindowInfo *window, int mode, int forceDefaults)
4412 {
4413     char *delimiters;
4414     int i, wrapMode, indentStyle, tabDist, emTabDist, highlight, oldEmTabDist;
4415     int wrapModeIsDef, tabDistIsDef, emTabDistIsDef, indentStyleIsDef;
4416     int highlightIsDef, haveHighlightPatterns, haveSmartIndentMacros;
4417     int oldMode = window->languageMode;
4418 
4419     /* If the mode is the same, and changes aren't being forced (as might
4420        happen with Save As...), don't mess with already correct settings */
4421     if (window->languageMode == mode && !forceDefaults)
4422 	return;
4423 
4424     /* Change the mode name stored in the window */
4425     window->languageMode = mode;
4426 
4427     /* Decref oldMode's default calltips file if needed */
4428     if (oldMode != PLAIN_LANGUAGE_MODE && LanguageModes[oldMode]->defTipsFile) {
4429         DeleteTagsFile( LanguageModes[oldMode]->defTipsFile, TIP, False );
4430     }
4431 
4432     /* Set delimiters for all text widgets */
4433     if (mode == PLAIN_LANGUAGE_MODE || LanguageModes[mode]->delimiters == NULL)
4434     	delimiters = GetPrefDelimiters();
4435     else
4436     	delimiters = LanguageModes[mode]->delimiters;
4437     XtVaSetValues(window->textArea, textNwordDelimiters, delimiters, NULL);
4438     for (i=0; i<window->nPanes; i++)
4439     	XtVaSetValues(window->textPanes[i], textNautoIndent, delimiters, NULL);
4440 
4441     /* Decide on desired values for language-specific parameters.  If a
4442        parameter was set to its default value, set it to the new default,
4443        otherwise, leave it alone */
4444     wrapModeIsDef = window->wrapMode == GetPrefWrap(oldMode);
4445     tabDistIsDef = BufGetTabDistance(window->buffer) == GetPrefTabDist(oldMode);
4446     XtVaGetValues(window->textArea, textNemulateTabs, &oldEmTabDist, NULL);
4447     emTabDistIsDef = oldEmTabDist == GetPrefEmTabDist(oldMode);
4448     indentStyleIsDef = window->indentStyle == GetPrefAutoIndent(oldMode) ||
4449 	    (GetPrefAutoIndent(oldMode) == SMART_INDENT &&
4450 	     window->indentStyle == AUTO_INDENT &&
4451 	     !SmartIndentMacrosAvailable(LanguageModeName(oldMode)));
4452     highlightIsDef = window->highlightSyntax == GetPrefHighlightSyntax()
4453 	    || (GetPrefHighlightSyntax() &&
4454 		 FindPatternSet(LanguageModeName(oldMode)) == NULL);
4455     wrapMode = wrapModeIsDef || forceDefaults ?
4456     	    GetPrefWrap(mode) : window->wrapMode;
4457     tabDist = tabDistIsDef || forceDefaults ?
4458 	    GetPrefTabDist(mode) : BufGetTabDistance(window->buffer);
4459     emTabDist = emTabDistIsDef || forceDefaults ?
4460 	    GetPrefEmTabDist(mode) : oldEmTabDist;
4461     indentStyle = indentStyleIsDef || forceDefaults ?
4462     	    GetPrefAutoIndent(mode) : window->indentStyle;
4463     highlight = highlightIsDef || forceDefaults ?
4464 	    GetPrefHighlightSyntax() : window->highlightSyntax;
4465 
4466     /* Dim/undim smart-indent and highlighting menu items depending on
4467        whether patterns/macros are available */
4468     haveHighlightPatterns = FindPatternSet(LanguageModeName(mode)) != NULL;
4469     haveSmartIndentMacros = SmartIndentMacrosAvailable(LanguageModeName(mode));
4470     if (IsTopDocument(window)) {
4471 	XtSetSensitive(window->highlightItem, haveHighlightPatterns);
4472 	XtSetSensitive(window->smartIndentItem, haveSmartIndentMacros);
4473     }
4474 
4475     /* Turn off requested options which are not available */
4476     highlight = haveHighlightPatterns && highlight;
4477     if (indentStyle == SMART_INDENT && !haveSmartIndentMacros)
4478 	indentStyle = AUTO_INDENT;
4479 
4480     /* Change highlighting */
4481     window->highlightSyntax = highlight;
4482     SetToggleButtonState(window, window->highlightItem, highlight, False);
4483     StopHighlighting(window);
4484 
4485     /* we defer highlighting to RaiseDocument() if doc is hidden */
4486     if (IsTopDocument(window) && highlight)
4487     	StartHighlighting(window, False);
4488 
4489     /* Force a change of smart indent macros (SetAutoIndent will re-start) */
4490     if (window->indentStyle == SMART_INDENT) {
4491 	EndSmartIndent(window);
4492 	window->indentStyle = AUTO_INDENT;
4493     }
4494 
4495     /* set requested wrap, indent, and tabs */
4496     SetAutoWrap(window, wrapMode);
4497     SetAutoIndent(window, indentStyle);
4498     SetTabDist(window, tabDist);
4499     SetEmTabDist(window, emTabDist);
4500 
4501     /* Load calltips files for new mode */
4502     if (mode != PLAIN_LANGUAGE_MODE && LanguageModes[mode]->defTipsFile) {
4503         AddTagsFile( LanguageModes[mode]->defTipsFile, TIP );
4504     }
4505 
4506     /* Add/remove language specific menu items */
4507     UpdateUserMenus(window);
4508 }
4509 
4510 /*
4511 ** Find and return the name of the appropriate languange mode for
4512 ** the file in "window".  Returns a pointer to a string, which will
4513 ** remain valid until a change is made to the language modes list.
4514 */
matchLanguageMode(WindowInfo * window)4515 static int matchLanguageMode(WindowInfo *window)
4516 {
4517     char *ext, *first200;
4518     int i, j, fileNameLen, extLen, beginPos, endPos, start;
4519     const char *versionExtendedPath;
4520 
4521     /*... look for an explicit mode statement first */
4522 
4523     /* Do a regular expression search on for recognition pattern */
4524     first200 = BufGetRange(window->buffer, 0, 200);
4525     for (i=0; i<NLanguageModes; i++) {
4526     	if (LanguageModes[i]->recognitionExpr != NULL) {
4527     	    if (SearchString(first200, LanguageModes[i]->recognitionExpr,
4528     	    	    SEARCH_FORWARD, SEARCH_REGEX, False, 0, &beginPos,
4529     	    	    &endPos, NULL, NULL, NULL))
4530             {
4531 		NEditFree(first200);
4532     	    	return i;
4533 	    }
4534     	}
4535     }
4536     NEditFree(first200);
4537 
4538     /* Look at file extension ("@@/" starts a ClearCase version extended path,
4539        which gets appended after the file extension, and therefore must be
4540        stripped off to recognize the extension to make ClearCase users happy) */
4541     fileNameLen = strlen(window->filename);
4542 #ifdef VMS
4543     if (strchr(window->filename, ';') != NULL)
4544     	fileNameLen = strchr(window->filename, ';') - window->filename;
4545 #else
4546     if ((versionExtendedPath = GetClearCaseVersionExtendedPath(window->filename)) != NULL)
4547         fileNameLen = versionExtendedPath - window->filename;
4548 #endif
4549     for (i=0; i<NLanguageModes; i++) {
4550     	for (j=0; j<LanguageModes[i]->nExtensions; j++) {
4551     	    ext = LanguageModes[i]->extensions[j];
4552     	    extLen = strlen(ext);
4553     	    start = fileNameLen - extLen;
4554 #if defined(__VMS) && (__VMS_VER >= 70200000)
4555           /* VMS v7.2 has case-preserving filenames */
4556             if (start >= 0 && !strncasecmp(&window->filename[start], ext, extLen))
4557                return i;
4558 #else
4559             if (start >= 0 && !strncmp(&window->filename[start], ext, extLen))
4560                 return i;
4561 #endif
4562     	}
4563     }
4564 
4565     /* no appropriate mode was found */
4566     return PLAIN_LANGUAGE_MODE;
4567 }
4568 
loadLanguageModesString(char * inString,int fileVer)4569 static int loadLanguageModesString(char *inString, int fileVer)
4570 {
4571     char *errMsg, *styleName, *inPtr = inString;
4572     languageModeRec *lm;
4573     int i;
4574 
4575     for (;;) {
4576 
4577 	/* skip over blank space */
4578 	inPtr += strspn(inPtr, " \t\n");
4579 
4580 	/* Allocate a language mode structure to return, set unread fields to
4581 	   empty so everything can be freed on errors by freeLanguageModeRec */
4582 	lm = (languageModeRec *)NEditMalloc(sizeof(languageModeRec));
4583 	lm->nExtensions = 0;
4584 	lm->recognitionExpr = NULL;
4585         lm->defTipsFile = NULL;
4586 	lm->delimiters = NULL;
4587 
4588 	/* read language mode name */
4589 	lm->name = ReadSymbolicField(&inPtr);
4590 	if (lm->name == NULL) {
4591     	    NEditFree(lm);
4592     	    return modeError(NULL,inString,inPtr,"language mode name required");
4593 	}
4594 	if (!SkipDelimiter(&inPtr, &errMsg))
4595     	    return modeError(lm, inString, inPtr, errMsg);
4596 
4597     	/* read list of extensions */
4598     	lm->extensions = readExtensionList(&inPtr,
4599     	    	&lm->nExtensions);
4600 	if (!SkipDelimiter(&inPtr, &errMsg))
4601     	    return modeError(lm, inString, inPtr, errMsg);
4602 
4603 	/* read the recognition regular expression */
4604 	if (*inPtr == '\n' || *inPtr == '\0' || *inPtr == ':')
4605     	    lm->recognitionExpr = NULL;
4606     	else if (!ReadQuotedString(&inPtr, &errMsg, &lm->recognitionExpr))
4607     	    return modeError(lm, inString,inPtr, errMsg);
4608 	if (!SkipDelimiter(&inPtr, &errMsg))
4609     	    return modeError(lm, inString, inPtr, errMsg);
4610 
4611     	/* read the indent style */
4612     	styleName = ReadSymbolicField(&inPtr);
4613 	if (styleName == NULL)
4614     	    lm->indentStyle = DEFAULT_INDENT;
4615     	else {
4616 	    for (i=0; i<N_INDENT_STYLES; i++) {
4617 	    	if (!strcmp(styleName, AutoIndentTypes[i])) {
4618 	    	    lm->indentStyle = i;
4619 	    	    break;
4620 	    	}
4621 	    }
4622 	    NEditFree(styleName);
4623 	    if (i == N_INDENT_STYLES)
4624 	    	return modeError(lm,inString,inPtr,"unrecognized indent style");
4625 	}
4626 	if (!SkipDelimiter(&inPtr, &errMsg))
4627     	    return modeError(lm, inString, inPtr, errMsg);
4628 
4629     	/* read the wrap style */
4630     	styleName = ReadSymbolicField(&inPtr);
4631 	if (styleName == NULL)
4632     	    lm->wrapStyle = DEFAULT_WRAP;
4633     	else {
4634 	    for (i=0; i<N_WRAP_STYLES; i++) {
4635 	    	if (!strcmp(styleName, AutoWrapTypes[i])) {
4636 	    	    lm->wrapStyle = i;
4637 	    	    break;
4638 	    	}
4639 	    }
4640 	    NEditFree(styleName);
4641 	    if (i == N_WRAP_STYLES)
4642 	    	return modeError(lm, inString, inPtr,"unrecognized wrap style");
4643 	}
4644 	if (!SkipDelimiter(&inPtr, &errMsg))
4645     	    return modeError(lm, inString, inPtr, errMsg);
4646 
4647     	/* read the tab distance */
4648 	if (*inPtr == '\n' || *inPtr == '\0' || *inPtr == ':')
4649     	    lm->tabDist = DEFAULT_TAB_DIST;
4650     	else if (!ReadNumericField(&inPtr, &lm->tabDist))
4651     	    return modeError(lm, inString, inPtr, "bad tab spacing");
4652 	if (!SkipDelimiter(&inPtr, &errMsg))
4653     	    return modeError(lm, inString, inPtr, errMsg);
4654 
4655     	/* read emulated tab distance */
4656     	if (*inPtr == '\n' || *inPtr == '\0' || *inPtr == ':')
4657     	    lm->emTabDist = DEFAULT_EM_TAB_DIST;
4658     	else if (!ReadNumericField(&inPtr, &lm->emTabDist))
4659     	    return modeError(lm, inString, inPtr, "bad emulated tab spacing");
4660 	if (!SkipDelimiter(&inPtr, &errMsg))
4661     	    return modeError(lm, inString, inPtr, errMsg);
4662 
4663 	/* read the delimiters string */
4664 	if (*inPtr == '\n' || *inPtr == '\0' || *inPtr == ':')
4665     	    lm->delimiters = NULL;
4666     	else if (!ReadQuotedString(&inPtr, &errMsg, &lm->delimiters))
4667     	    return modeError(lm, inString, inPtr, errMsg);
4668 
4669         /* After 5.3 all language modes need a default tips file field */
4670 	if (!SkipDelimiter(&inPtr, &errMsg))
4671             if (fileVer > 5003)
4672     	        return modeError(lm, inString, inPtr, errMsg);
4673 
4674         /* read the default tips file */
4675 	if (*inPtr == '\n' || *inPtr == '\0')
4676     	    lm->defTipsFile = NULL;
4677     	else if (!ReadQuotedString(&inPtr, &errMsg, &lm->defTipsFile))
4678     	    return modeError(lm, inString, inPtr, errMsg);
4679 
4680    	/* pattern set was read correctly, add/replace it in the list */
4681    	for (i=0; i<NLanguageModes; i++) {
4682 	    if (!strcmp(LanguageModes[i]->name, lm->name)) {
4683 		freeLanguageModeRec(LanguageModes[i]);
4684 		LanguageModes[i] = lm;
4685 		break;
4686 	    }
4687 	}
4688 	if (i == NLanguageModes) {
4689 	    LanguageModes[NLanguageModes++] = lm;
4690    	    if (NLanguageModes > MAX_LANGUAGE_MODES)
4691    		return modeError(NULL, inString, inPtr,
4692    	    		"maximum allowable number of language modes exceeded");
4693 	}
4694 
4695     	/* if the string ends here, we're done */
4696    	inPtr += strspn(inPtr, " \t\n");
4697     	if (*inPtr == '\0')
4698     	    return True;
4699     } /* End for(;;) */
4700 }
4701 
writeLanguageModesString(void)4702 static char *writeLanguageModesString(void)
4703 {
4704     int i;
4705     char *outStr, *escapedStr, *str, numBuf[25];
4706     textBuffer *outBuf;
4707 
4708     outBuf = BufCreate();
4709     for (i=0; i<NLanguageModes; i++) {
4710     	BufInsert(outBuf, outBuf->length, "\t");
4711     	BufInsert(outBuf, outBuf->length, LanguageModes[i]->name);
4712     	BufInsert(outBuf, outBuf->length, ":");
4713     	BufInsert(outBuf, outBuf->length, str = createExtString(
4714     	    	LanguageModes[i]->extensions, LanguageModes[i]->nExtensions));
4715     	NEditFree(str);
4716     	BufInsert(outBuf, outBuf->length, ":");
4717     	if (LanguageModes[i]->recognitionExpr != NULL) {
4718     	    BufInsert(outBuf, outBuf->length,
4719     	    	    str=MakeQuotedString(LanguageModes[i]->recognitionExpr));
4720     	    NEditFree(str);
4721     	}
4722     	BufInsert(outBuf, outBuf->length, ":");
4723     	if (LanguageModes[i]->indentStyle != DEFAULT_INDENT)
4724     	    BufInsert(outBuf, outBuf->length,
4725     	    	    AutoIndentTypes[LanguageModes[i]->indentStyle]);
4726     	BufInsert(outBuf, outBuf->length, ":");
4727     	if (LanguageModes[i]->wrapStyle != DEFAULT_WRAP)
4728     	    BufInsert(outBuf, outBuf->length,
4729     	    	    AutoWrapTypes[LanguageModes[i]->wrapStyle]);
4730     	BufInsert(outBuf, outBuf->length, ":");
4731     	if (LanguageModes[i]->tabDist != DEFAULT_TAB_DIST) {
4732     	    sprintf(numBuf, "%d", LanguageModes[i]->tabDist);
4733     	    BufInsert(outBuf, outBuf->length, numBuf);
4734     	}
4735     	BufInsert(outBuf, outBuf->length, ":");
4736     	if (LanguageModes[i]->emTabDist != DEFAULT_EM_TAB_DIST) {
4737     	    sprintf(numBuf, "%d", LanguageModes[i]->emTabDist);
4738     	    BufInsert(outBuf, outBuf->length, numBuf);
4739     	}
4740     	BufInsert(outBuf, outBuf->length, ":");
4741     	if (LanguageModes[i]->delimiters != NULL) {
4742     	    BufInsert(outBuf, outBuf->length,
4743     	    	    str=MakeQuotedString(LanguageModes[i]->delimiters));
4744     	    NEditFree(str);
4745     	}
4746     	BufInsert(outBuf, outBuf->length, ":");
4747     	if (LanguageModes[i]->defTipsFile != NULL) {
4748     	    BufInsert(outBuf, outBuf->length,
4749     	    	    str=MakeQuotedString(LanguageModes[i]->defTipsFile));
4750     	    NEditFree(str);
4751     	}
4752 
4753     	BufInsert(outBuf, outBuf->length, "\n");
4754     }
4755 
4756     /* Get the output, and lop off the trailing newline */
4757     outStr = BufGetRange(outBuf, 0, outBuf->length - 1);
4758     BufFree(outBuf);
4759     escapedStr = EscapeSensitiveChars(outStr);
4760     NEditFree(outStr);
4761     return escapedStr;
4762 }
4763 
createExtString(char ** extensions,int nExtensions)4764 static char *createExtString(char **extensions, int nExtensions)
4765 {
4766     int e, length = 1;
4767     char *outStr, *outPtr;
4768 
4769     for (e=0; e<nExtensions; e++)
4770     	length += strlen(extensions[e]) + 1;
4771     outStr = outPtr = (char*)NEditMalloc(length);
4772     for (e=0; e<nExtensions; e++) {
4773     	strcpy(outPtr, extensions[e]);
4774     	outPtr += strlen(extensions[e]);
4775     	*outPtr++ = ' ';
4776     }
4777     if (nExtensions == 0)
4778     	*outPtr = '\0';
4779     else
4780     	*(outPtr-1) = '\0';
4781     return outStr;
4782 }
4783 
readExtensionList(char ** inPtr,int * nExtensions)4784 static char **readExtensionList(char **inPtr, int *nExtensions)
4785 {
4786     char *extensionList[MAX_FILE_EXTENSIONS];
4787     char **retList, *strStart;
4788     int i, len;
4789 
4790     /* skip over blank space */
4791     *inPtr += strspn(*inPtr, " \t");
4792 
4793     for (i=0; i<MAX_FILE_EXTENSIONS && **inPtr!=':' && **inPtr!='\0'; i++) {
4794     	*inPtr += strspn(*inPtr, " \t");
4795 	strStart = *inPtr;
4796 	while (**inPtr!=' ' && **inPtr!='\t' && **inPtr!=':' && **inPtr!='\0')
4797 	    (*inPtr)++;
4798     	len = *inPtr - strStart;
4799     	extensionList[i] = (char*)NEditMalloc(len + 1);
4800     	strncpy(extensionList[i], strStart, len);
4801     	extensionList[i][len] = '\0';
4802     }
4803     *nExtensions = i;
4804     if (i == 0)
4805     	return NULL;
4806     retList = (char **)NEditMalloc(sizeof(char *) * i);
4807     memcpy(retList, extensionList, sizeof(char *) * i);
4808     return retList;
4809 }
4810 
ReadNumericField(char ** inPtr,int * value)4811 int ReadNumericField(char **inPtr, int *value)
4812 {
4813     int charsRead;
4814 
4815     /* skip over blank space */
4816     *inPtr += strspn(*inPtr, " \t");
4817 
4818     if (sscanf(*inPtr, "%d%n", value, &charsRead) != 1)
4819     	return False;
4820     *inPtr += charsRead;
4821     return True;
4822 }
4823 
4824 /*
4825 ** Parse a symbolic field, skipping initial and trailing whitespace,
4826 ** stops on first invalid character or end of string.  Valid characters
4827 ** are letters, numbers, _, -, +, $, #, and internal whitespace.  Internal
4828 ** whitespace is compressed to single space characters.
4829 */
ReadSymbolicField(char ** inPtr)4830 char *ReadSymbolicField(char **inPtr)
4831 {
4832     char *outStr, *outPtr, *strStart, *strPtr;
4833     int len;
4834 
4835     /* skip over initial blank space */
4836     *inPtr += strspn(*inPtr, " \t");
4837 
4838     /* Find the first invalid character or end of string to know how
4839        much memory to allocate for the returned string */
4840     strStart = *inPtr;
4841     while (isalnum((unsigned char)**inPtr) || **inPtr=='_' || **inPtr=='-' ||
4842       	    **inPtr=='+' || **inPtr=='$' || **inPtr=='#' || **inPtr==' ' ||
4843       	    **inPtr=='\t')
4844     	(*inPtr)++;
4845     len = *inPtr - strStart;
4846     if (len == 0)
4847     	return NULL;
4848     outStr = outPtr = (char*)NEditMalloc(len + 1);
4849 
4850     /* Copy the string, compressing internal whitespace to a single space */
4851     strPtr = strStart;
4852     while (strPtr - strStart < len) {
4853     	if (*strPtr == ' ' || *strPtr == '\t') {
4854     	    strPtr += strspn(strPtr, " \t");
4855     	    *outPtr++ = ' ';
4856     	} else
4857     	    *outPtr++ = *strPtr++;
4858     }
4859 
4860     /* If there's space on the end, take it back off */
4861     if (outPtr > outStr && *(outPtr-1) == ' ')
4862     	outPtr--;
4863     if (outPtr == outStr) {
4864     	NEditFree(outStr);
4865     	return NULL;
4866     }
4867     *outPtr = '\0';
4868     return outStr;
4869 }
4870 
4871 /*
4872 ** parse an individual quoted string.  Anything between
4873 ** double quotes is acceptable, quote characters can be escaped by "".
4874 ** Returns allocated string "string" containing
4875 ** argument minus quotes.  If not successful, returns False with
4876 ** (statically allocated) message in "errMsg".
4877 */
ReadQuotedString(char ** inPtr,char ** errMsg,char ** string)4878 int ReadQuotedString(char **inPtr, char **errMsg, char **string)
4879 {
4880     char *outPtr, *c;
4881 
4882     /* skip over blank space */
4883     *inPtr += strspn(*inPtr, " \t");
4884 
4885     /* look for initial quote */
4886     if (**inPtr != '\"') {
4887     	*errMsg = "expecting quoted string";
4888     	return False;
4889     }
4890     (*inPtr)++;
4891 
4892     /* calculate max length and allocate returned string */
4893     for (c= *inPtr; ; c++) {
4894     	if (*c == '\0') {
4895     	    *errMsg = "string not terminated";
4896     	    return False;
4897     	} else if (*c == '\"') {
4898     	    if (*(c+1) == '\"')
4899     	    	c++;
4900     	    else
4901     	    	break;
4902     	}
4903     }
4904 
4905     /* copy string up to end quote, transforming escaped quotes into quotes */
4906     *string = (char*)NEditMalloc(c - *inPtr + 1);
4907     outPtr = *string;
4908     while (True) {
4909     	if (**inPtr == '\"') {
4910     	    if (*(*inPtr+1) == '\"')
4911     	    	(*inPtr)++;
4912     	    else
4913     	    	break;
4914     	}
4915     	*outPtr++ = *(*inPtr)++;
4916     }
4917     *outPtr = '\0';
4918 
4919     /* skip end quote */
4920     (*inPtr)++;
4921     return True;
4922 }
4923 
4924 /*
4925 ** Replace characters which the X resource file reader considers control
4926 ** characters, such that a string will read back as it appears in "string".
4927 ** (So far, newline characters are replaced with with \n\<newline> and
4928 ** backslashes with \\.  This has not been tested exhaustively, and
4929 ** probably should be.  It would certainly be more asthetic if other
4930 ** control characters were replaced as well).
4931 **
4932 ** Returns an allocated string which must be freed by the caller with NEditFree.
4933 */
EscapeSensitiveChars(const char * string)4934 char *EscapeSensitiveChars(const char *string)
4935 {
4936     const char *c;
4937     char *outStr, *outPtr;
4938     int length = 0;
4939 
4940     /* calculate length and allocate returned string */
4941     for (c=string; *c!='\0'; c++) {
4942     	if (*c == '\\')
4943     	    length++;
4944     	else if (*c == '\n')
4945     	    length += 3;
4946     	length++;
4947     }
4948     outStr = (char*)NEditMalloc(length + 1);
4949     outPtr = outStr;
4950 
4951     /* add backslashes */
4952     for (c=string; *c!='\0'; c++) {
4953     	if (*c == '\\')
4954     	    *outPtr++ = '\\';
4955     	else if (*c == '\n') {
4956     	    *outPtr++ = '\\';
4957     	    *outPtr++ = 'n';
4958     	    *outPtr++ = '\\';
4959     	}
4960     	*outPtr++ = *c;
4961     }
4962     *outPtr = '\0';
4963     return outStr;
4964 }
4965 
4966 /*
4967 ** Adds double quotes around a string and escape existing double quote
4968 ** characters with two double quotes.  Enables the string to be read back
4969 ** by ReadQuotedString.
4970 */
MakeQuotedString(const char * string)4971 char *MakeQuotedString(const char *string)
4972 {
4973     const char *c;
4974     char *outStr, *outPtr;
4975     int length = 0;
4976 
4977     /* calculate length and allocate returned string */
4978     for (c=string; *c!='\0'; c++) {
4979     	if (*c == '\"')
4980     	    length++;
4981     	length++;
4982     }
4983     outStr = (char*)NEditMalloc(length + 3);
4984     outPtr = outStr;
4985 
4986     /* add starting quote */
4987     *outPtr++ = '\"';
4988 
4989     /* copy string, escaping quotes with "" */
4990     for (c=string; *c!='\0'; c++) {
4991     	if (*c == '\"')
4992     	    *outPtr++ = '\"';
4993     	*outPtr++ = *c;
4994     }
4995 
4996     /* add ending quote */
4997     *outPtr++ = '\"';
4998 
4999     /* terminate string and return */
5000     *outPtr = '\0';
5001     return outStr;
5002 }
5003 
5004 /*
5005 ** Read a dialog text field containing a symbolic name (language mode names,
5006 ** style names, highlight pattern names, colors, and fonts), clean the
5007 ** entered text of leading and trailing whitespace, compress all
5008 ** internal whitespace to one space character, and check it over for
5009 ** colons, which interfere with the preferences file reader/writer syntax.
5010 ** Returns NULL on error, and puts up a dialog if silent is False.  Returns
5011 ** an empty string if the text field is blank.
5012 */
ReadSymbolicFieldTextWidget(Widget textW,const char * fieldName,int silent)5013 char *ReadSymbolicFieldTextWidget(Widget textW, const char *fieldName, int silent)
5014 {
5015     char *string, *stringPtr, *parsedString;
5016 
5017     /* read from the text widget */
5018     string = stringPtr = XmTextGetString(textW);
5019 
5020     /* parse it with the same routine used to read symbolic fields from
5021        files.  If the string is not read entirely, there are invalid
5022        characters, so warn the user if not in silent mode. */
5023     parsedString = ReadSymbolicField(&stringPtr);
5024     if (*stringPtr != '\0')
5025     {
5026         if (!silent)
5027         {
5028             *(stringPtr + 1) = '\0';
5029             DialogF(DF_WARN, textW, 1, "Invalid Character",
5030                     "Invalid character \"%s\" in %s", "OK", stringPtr,
5031                     fieldName);
5032             XmProcessTraversal(textW, XmTRAVERSE_CURRENT);
5033         }
5034         NEditFree(string);
5035         NEditFree(parsedString);
5036         return NULL;
5037     }
5038     NEditFree(string);
5039     if (parsedString == NULL) {
5040     	parsedString = NEditStrdup("");
5041     }
5042     return parsedString;
5043 }
5044 
5045 /*
5046 ** Create a pulldown menu pane with the names of the current language modes.
5047 ** XmNuserData for each item contains the language mode name.
5048 */
CreateLanguageModeMenu(Widget parent,XtCallbackProc cbProc,void * cbArg)5049 Widget CreateLanguageModeMenu(Widget parent, XtCallbackProc cbProc, void *cbArg)
5050 {
5051     Widget menu, btn;
5052     int i;
5053     XmString s1;
5054 
5055     menu = CreatePulldownMenu(parent, "languageModes", NULL, 0);
5056     for (i=0; i<NLanguageModes; i++) {
5057         btn = XtVaCreateManagedWidget("languageMode", xmPushButtonGadgetClass,
5058         	menu,
5059         	XmNlabelString, s1=XmStringCreateSimple(LanguageModes[i]->name),
5060 		XmNmarginHeight, 0,
5061     		XmNuserData, (void *)LanguageModes[i]->name, NULL);
5062         XmStringFree(s1);
5063 	XtAddCallback(btn, XmNactivateCallback, cbProc, cbArg);
5064     }
5065     return menu;
5066 }
5067 
5068 /*
5069 ** Set the language mode menu in option menu "optMenu" to
5070 ** show a particular language mode
5071 */
SetLangModeMenu(Widget optMenu,const char * modeName)5072 void SetLangModeMenu(Widget optMenu, const char *modeName)
5073 {
5074     int i;
5075     Cardinal nItems;
5076     WidgetList items;
5077     Widget pulldown, selectedItem;
5078     char *itemName;
5079 
5080     XtVaGetValues(optMenu, XmNsubMenuId, &pulldown, NULL);
5081     XtVaGetValues(pulldown, XmNchildren, &items, XmNnumChildren, &nItems, NULL);
5082     if (nItems == 0)
5083     	return;
5084     selectedItem = items[0];
5085     for (i=0; i<(int)nItems; i++) {
5086     	XtVaGetValues(items[i], XmNuserData, &itemName, NULL);
5087     	if (!strcmp(itemName, modeName)) {
5088     	    selectedItem = items[i];
5089     	    break;
5090     	}
5091     }
5092     XtVaSetValues(optMenu, XmNmenuHistory, selectedItem,NULL);
5093 }
5094 
5095 /*
5096 ** Create a submenu for chosing language mode for the current window.
5097 */
CreateLanguageModeSubMenu(WindowInfo * window,const Widget parent,const char * name,const char * label,char mnemonic)5098 void CreateLanguageModeSubMenu(WindowInfo* window, const Widget parent,
5099         const char* name, const char* label, char mnemonic)
5100 {
5101     XmString string = XmStringCreateSimple((char*) label);
5102 
5103     window->langModeCascade = XtVaCreateManagedWidget(name,
5104             xmCascadeButtonGadgetClass, parent,
5105             XmNlabelString, string,
5106             XmNmnemonic, mnemonic,
5107             XmNsubMenuId, NULL,
5108             NULL);
5109     XmStringFree(string);
5110 
5111     updateLanguageModeSubmenu(window);
5112 }
5113 
5114 /*
5115 ** Re-build the language mode sub-menu using the current data stored
5116 ** in the master list: LanguageModes.
5117 */
updateLanguageModeSubmenu(WindowInfo * window)5118 static void updateLanguageModeSubmenu(WindowInfo *window)
5119 {
5120     int i;
5121     XmString s1;
5122     Widget menu, btn;
5123     Arg args[1] = {{XmNradioBehavior, (XtArgVal)True}};
5124 
5125     /* Destroy and re-create the menu pane */
5126     XtVaGetValues(window->langModeCascade, XmNsubMenuId, &menu, NULL);
5127     if (menu != NULL)
5128     	XtDestroyWidget(menu);
5129     menu = CreatePulldownMenu(XtParent(window->langModeCascade),
5130     	    "languageModes", args, 1);
5131     btn = XtVaCreateManagedWidget("languageMode",
5132             xmToggleButtonGadgetClass, menu,
5133             XmNlabelString, s1=XmStringCreateSimple("Plain"),
5134     	    XmNuserData, (void *)PLAIN_LANGUAGE_MODE,
5135     	    XmNset, window->languageMode==PLAIN_LANGUAGE_MODE, NULL);
5136     XmStringFree(s1);
5137     XtAddCallback(btn, XmNvalueChangedCallback, setLangModeCB, window);
5138     for (i=0; i<NLanguageModes; i++) {
5139         btn = XtVaCreateManagedWidget("languageMode",
5140             	xmToggleButtonGadgetClass, menu,
5141             	XmNlabelString, s1=XmStringCreateSimple(LanguageModes[i]->name),
5142  	    	XmNmarginHeight, 0,
5143    		XmNuserData, (void *)(intptr_t)i,
5144     		XmNset, window->languageMode==i, NULL);
5145         XmStringFree(s1);
5146 	XtAddCallback(btn, XmNvalueChangedCallback, setLangModeCB, window);
5147     }
5148     XtVaSetValues(window->langModeCascade, XmNsubMenuId, menu, NULL);
5149 }
5150 
setLangModeCB(Widget w,XtPointer clientData,XtPointer callData)5151 static void setLangModeCB(Widget w, XtPointer clientData, XtPointer callData)
5152 {
5153     WindowInfo *window = WidgetToWindow(MENU_WIDGET(w));
5154     char *params[1];
5155     void *mode;
5156 
5157     if (!XmToggleButtonGetState(w))
5158     	return;
5159 
5160     /* get name of language mode stored in userData field of menu item */
5161     XtVaGetValues(w, XmNuserData, &mode, NULL);
5162 
5163     /* If the mode didn't change, do nothing */
5164     if (window->languageMode == (int)(intptr_t)mode)
5165     	return;
5166 
5167     /* redo syntax highlighting word delimiters, etc. */
5168 /*
5169     reapplyLanguageMode(window, (int)mode, False);
5170 */
5171     params[0] = (((int)(intptr_t)mode) == PLAIN_LANGUAGE_MODE) ? "" : LanguageModes[(int)(intptr_t)mode]->name;
5172     XtCallActionProc(window->textArea, "set_language_mode", NULL, params, 1);
5173 }
5174 
5175 /*
5176 ** Skip a delimiter and it's surrounding whitespace
5177 */
SkipDelimiter(char ** inPtr,char ** errMsg)5178 int SkipDelimiter(char **inPtr, char **errMsg)
5179 {
5180     *inPtr += strspn(*inPtr, " \t");
5181     if (**inPtr != ':') {
5182     	*errMsg = "syntax error";
5183     	return False;
5184     }
5185     (*inPtr)++;
5186     *inPtr += strspn(*inPtr, " \t");
5187     return True;
5188 }
5189 
5190 /*
5191 ** Skip an optional separator and its surrounding whitespace
5192 ** return true if delimiter found
5193 */
SkipOptSeparator(char separator,char ** inPtr)5194 int SkipOptSeparator(char separator, char **inPtr)
5195 {
5196     *inPtr += strspn(*inPtr, " \t");
5197     if (**inPtr != separator) {
5198     	return False;
5199     }
5200     (*inPtr)++;
5201     *inPtr += strspn(*inPtr, " \t");
5202     return True;
5203 }
5204 
5205 /*
5206 ** Short-hand error processing for language mode parsing errors, frees
5207 ** lm (if non-null), prints a formatted message explaining where the
5208 ** error is, and returns False;
5209 */
modeError(languageModeRec * lm,const char * stringStart,const char * stoppedAt,const char * message)5210 static int modeError(languageModeRec *lm, const char *stringStart,
5211         const char *stoppedAt, const char *message)
5212 {
5213     if (lm != NULL)
5214     	freeLanguageModeRec(lm);
5215     return ParseError(NULL, stringStart, stoppedAt,
5216     	    "language mode specification", message);
5217 }
5218 
5219 /*
5220 ** Report parsing errors in resource strings or macros, formatted nicely so
5221 ** the user can tell where things became botched.  Errors can be sent either
5222 ** to stderr, or displayed in a dialog.  For stderr, pass toDialog as NULL.
5223 ** For a dialog, pass the dialog parent in toDialog.
5224 */
ParseError(Widget toDialog,const char * stringStart,const char * stoppedAt,const char * errorIn,const char * message)5225 int ParseError(Widget toDialog, const char *stringStart, const char *stoppedAt,
5226 	const char *errorIn, const char *message)
5227 {
5228     int len, nNonWhite = 0;
5229     const char *c;
5230     char *errorLine;
5231 
5232     for (c=stoppedAt; c>=stringStart; c--) {
5233     	if (c == stringStart)
5234     	    break;
5235     	else if (*c == '\n' && nNonWhite >= 5)
5236     	    break;
5237     	else if (*c != ' ' && *c != '\t')
5238     	    nNonWhite++;
5239     }
5240     len = stoppedAt - c + (*stoppedAt == '\0' ? 0 : 1);
5241     errorLine = (char*)NEditMalloc(len+4);
5242     strncpy(errorLine, c, len);
5243     errorLine[len++] = '<';
5244     errorLine[len++] = '=';
5245     errorLine[len++] = '=';
5246     errorLine[len] = '\0';
5247     if (toDialog == NULL)
5248     {
5249         fprintf(stderr, "NEdit: %s in %s:\n%s\n", message, errorIn, errorLine);
5250     } else
5251     {
5252         DialogF(DF_WARN, toDialog, 1, "Parse Error", "%s in %s:\n%s", "OK",
5253                 message, errorIn, errorLine);
5254     }
5255     NEditFree(errorLine);
5256     return False;
5257 }
5258 
5259 /*
5260 ** Compare two strings which may be NULL
5261 */
AllocatedStringsDiffer(const char * s1,const char * s2)5262 int AllocatedStringsDiffer(const char *s1, const char *s2)
5263 {
5264     if (s1 == NULL && s2 == NULL)
5265     	return False;
5266     if (s1 == NULL || s2 == NULL)
5267     	return True;
5268     return strcmp(s1, s2);
5269 }
5270 
updatePatternsTo5dot1(void)5271 static void updatePatternsTo5dot1(void)
5272 {
5273     const char *htmlDefaultExpr = "^[ \t]*HTML[ \t]*:[ \t]*Default[ \t]*$";
5274     const char *vhdlAnchorExpr = "^[ \t]*VHDL:";
5275 
5276     /* Add new patterns if there aren't already existing patterns with
5277        the same name.  If possible, insert before VHDL in language mode
5278        list.  If not, just add to end */
5279     if (!regexFind(TempStringPrefs.highlight, "^[ \t]*PostScript:"))
5280 	spliceString(&TempStringPrefs.highlight, "PostScript:Default",
5281 		vhdlAnchorExpr);
5282     if (!regexFind(TempStringPrefs.language, "^[ \t]*PostScript:"))
5283 	spliceString(&TempStringPrefs.language,
5284 		"PostScript:.ps .PS .eps .EPS .epsf .epsi::::::",
5285 		vhdlAnchorExpr);
5286     if (!regexFind(TempStringPrefs.highlight, "^[ \t]*Lex:"))
5287 	spliceString(&TempStringPrefs.highlight, "Lex:Default",
5288 		vhdlAnchorExpr);
5289     if (!regexFind(TempStringPrefs.language, "^[ \t]*Lex:"))
5290 	spliceString(&TempStringPrefs.language, "Lex:.lex::::::",
5291 		vhdlAnchorExpr);
5292     if (!regexFind(TempStringPrefs.highlight, "^[ \t]*SQL:"))
5293 	spliceString(&TempStringPrefs.highlight, "SQL:Default",
5294 		vhdlAnchorExpr);
5295     if (!regexFind(TempStringPrefs.language, "^[ \t]*SQL:"))
5296 	spliceString(&TempStringPrefs.language, "SQL:.sql::::::",
5297 		vhdlAnchorExpr);
5298     if (!regexFind(TempStringPrefs.highlight, "^[ \t]*Matlab:"))
5299 	spliceString(&TempStringPrefs.highlight, "Matlab:Default",
5300 		vhdlAnchorExpr);
5301     if (!regexFind(TempStringPrefs.language, "^[ \t]*Matlab:"))
5302 	spliceString(&TempStringPrefs.language, "Matlab:..m .oct .sci::::::",
5303 		vhdlAnchorExpr);
5304     if (!regexFind(TempStringPrefs.smartIndent, "^[ \t]*Matlab:"))
5305 	spliceString(&TempStringPrefs.smartIndent, "Matlab:Default", NULL);
5306     if (!regexFind(TempStringPrefs.styles, "^[ \t]*Label:"))
5307 	spliceString(&TempStringPrefs.styles, "Label:red:Italic",
5308 		"^[ \t]*Flag:");
5309     if (!regexFind(TempStringPrefs.styles, "^[ \t]*Storage Type1:"))
5310 	spliceString(&TempStringPrefs.styles, "Storage Type1:saddle brown:Bold",
5311 		"^[ \t]*String:");
5312 
5313     /* Replace html pattern with sgml html pattern, as long as there
5314        isn't an existing html pattern which will be overwritten */
5315     if (regexFind(TempStringPrefs.highlight, htmlDefaultExpr)) {
5316 	regexReplace(&TempStringPrefs.highlight, htmlDefaultExpr,
5317 	    	"SGML HTML:Default");
5318     	if (!regexReplace(&TempStringPrefs.language, "^[ \t]*HTML:.*$",
5319 	    	"SGML HTML:.sgml .sgm .html .htm:\"\\<(?ihtml)\\>\":::::\n")) {
5320 	    spliceString(&TempStringPrefs.language,
5321 		    "SGML HTML:.sgml .sgm .html .htm:\"\\<(?ihtml)\\>\":::::\n",
5322 		    vhdlAnchorExpr);
5323 	}
5324     }
5325 }
5326 
updatePatternsTo5dot2(void)5327 static void updatePatternsTo5dot2(void)
5328 {
5329 #ifdef VMS
5330     const char *cppLm5dot1 =
5331 	"^[ \t]*C\\+\\+:\\.CC \\.HH \\.I::::::\"\\.,/\\\\`'!\\|@#%\\^&\\*\\(\\)-=\\+\\{\\}\\[\\]\"\":;\\<\\>\\?~\"";
5332     const char *perlLm5dot1 =
5333 	"^[ \t]*Perl:\\.PL \\.PM \\.P5:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\.\\*perl\":::::";
5334     const char *psLm5dot1 =
5335         "^[ \t]*PostScript:\\.ps \\.PS \\.eps \\.EPS \\.epsf \\.epsi:\"\\^%!\":::::\"/%\\(\\)\\{\\}\\[\\]\\<\\>\"";
5336     const char *tclLm5dot1 = "^[ \t]*Tcl:\\.TCL::::::";
5337 
5338     const char *cppLm5dot2 =
5339         "C++:.CC .HH .C .H .I .CXX .HXX .CPP::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\"";
5340     const char *perlLm5dot2 =
5341         "Perl:.PL .PM .P5:\"^[ \\t]*#[ \\t]*!.*perl\":Auto:None:::\".,/\\\\`'!$@#%^&*()-=+{}[]\"\":;<>?~|\"";
5342     const char *psLm5dot2 =
5343         "PostScript:.ps .PS .eps .EPS .epsf .epsi:\"^%!\":::::\"/%(){}[]<>\"";
5344     const char *tclLm5dot2 =
5345         "Tcl:.TCL::Smart:None:::";
5346 #else
5347     const char *cppLm5dot1 =
5348 	"^[ \t]*C\\+\\+:\\.cc \\.hh \\.C \\.H \\.i \\.cxx \\.hxx::::::\"\\.,/\\\\`'!\\|@#%\\^&\\*\\(\\)-=\\+\\{\\}\\[\\]\"\":;\\<\\>\\?~\"";
5349     const char *perlLm5dot1 =
5350 	"^[ \t]*Perl:\\.pl \\.pm \\.p5:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\.\\*perl\":::::";
5351     const char *psLm5dot1 =
5352         "^[ \t]*PostScript:\\.ps \\.PS \\.eps \\.EPS \\.epsf \\.epsi:\"\\^%!\":::::\"/%\\(\\)\\{\\}\\[\\]\\<\\>\"";
5353     const char *shLm5dot1 =
5354         "^[ \t]*Sh Ksh Bash:\\.sh \\.bash \\.ksh \\.profile:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\[ \\\\t\\]\\*/bin/\\(sh\\|ksh\\|bash\\)\":::::";
5355     const char *tclLm5dot1 = "^[ \t]*Tcl:\\.tcl::::::";
5356 
5357     const char *cppLm5dot2 =
5358         "C++:.cc .hh .C .H .i .cxx .hxx .cpp::::::\".,/\\`'!|@#%^&*()-=+{}[]\"\":;<>?~\"";
5359     const char *perlLm5dot2 =
5360         "Perl:.pl .pm .p5 .PL:\"^[ \\t]*#[ \\t]*!.*perl\":Auto:None:::\".,/\\\\`'!$@#%^&*()-=+{}[]\"\":;<>?~|\"";
5361     const char *psLm5dot2 =
5362         "PostScript:.ps .eps .epsf .epsi:\"^%!\":::::\"/%(){}[]<>\"";
5363     const char *shLm5dot2 =
5364         "Sh Ksh Bash:.sh .bash .ksh .profile .bashrc .bash_logout .bash_login .bash_profile:\"^[ \\t]*#[ \\t]*![ \\t]*/.*bin/(sh|ksh|bash)\":::::";
5365     const char *tclLm5dot2 =
5366         "Tcl:.tcl .tk .itcl .itk::Smart:None:::";
5367 #endif /* VMS */
5368 
5369     const char *cssLm5dot2 =
5370         "CSS:css::Auto:None:::\".,/\\`'!|@#%^&*()=+{}[]\"\":;<>?~\"";
5371     const char *reLm5dot2 =
5372         "Regex:.reg .regex:\"\\(\\?[:#=!iInN].+\\)\":None:Continuous:::";
5373     const char *xmlLm5dot2 =
5374         "XML:.xml .xsl .dtd:\"\\<(?i\\?xml|!doctype)\"::None:::\"<>/=\"\"'()+*?|\"";
5375 
5376     const char *cssHl5dot2 = "CSS:Default";
5377     const char *reHl5dot2 =  "Regex:Default";
5378     const char *xmlHl5dot2 = "XML:Default";
5379 
5380     const char *ptrStyle = "Pointer:#660000:Bold";
5381     const char *reStyle = "Regex:#009944:Bold";
5382     const char *wrnStyle = "Warning:brown2:Italic";
5383 
5384     /* First upgrade modified language modes, only if the user hasn't
5385        altered the default 5.1 definitions. */
5386     if (regexFind(TempStringPrefs.language, cppLm5dot1))
5387 	regexReplace(&TempStringPrefs.language, cppLm5dot1, cppLm5dot2);
5388     if (regexFind(TempStringPrefs.language, perlLm5dot1))
5389 	regexReplace(&TempStringPrefs.language, perlLm5dot1, perlLm5dot2);
5390     if (regexFind(TempStringPrefs.language, psLm5dot1))
5391 	regexReplace(&TempStringPrefs.language, psLm5dot1, psLm5dot2);
5392 #ifndef VMS
5393     if (regexFind(TempStringPrefs.language, shLm5dot1))
5394 	regexReplace(&TempStringPrefs.language, shLm5dot1, shLm5dot2);
5395 #endif
5396     if (regexFind(TempStringPrefs.language, tclLm5dot1))
5397 	regexReplace(&TempStringPrefs.language, tclLm5dot1, tclLm5dot2);
5398 
5399     /* Then append the new modes (trying to keep them in alphabetical order
5400        makes no sense, since 5.1 didn't use alphabetical order). */
5401     if (!regexFind(TempStringPrefs.language, "^[ \t]*CSS:"))
5402 	spliceString(&TempStringPrefs.language, cssLm5dot2, NULL);
5403     if (!regexFind(TempStringPrefs.language, "^[ \t]*Regex:"))
5404 	spliceString(&TempStringPrefs.language, reLm5dot2, NULL);
5405     if (!regexFind(TempStringPrefs.language, "^[ \t]*XML:"))
5406 	spliceString(&TempStringPrefs.language, xmlLm5dot2, NULL);
5407 
5408     /* Enable default highlighting patterns for these modes, unless already
5409        present */
5410     if (!regexFind(TempStringPrefs.highlight, "^[ \t]*CSS:"))
5411 	spliceString(&TempStringPrefs.highlight, cssHl5dot2, NULL);
5412     if (!regexFind(TempStringPrefs.highlight, "^[ \t]*Regex:"))
5413 	spliceString(&TempStringPrefs.highlight, reHl5dot2, NULL);
5414     if (!regexFind(TempStringPrefs.highlight, "^[ \t]*XML:"))
5415 	spliceString(&TempStringPrefs.highlight, xmlHl5dot2, NULL);
5416 
5417     /* Finally, append the new highlight styles */
5418 
5419     if (!regexFind(TempStringPrefs.styles, "^[ \t]*Warning:"))
5420 	spliceString(&TempStringPrefs.styles, wrnStyle, NULL);
5421     if (!regexFind(TempStringPrefs.styles, "^[ \t]*Regex:"))
5422 	spliceString(&TempStringPrefs.styles, reStyle, "^[ \t]*Warning:");
5423     if (!regexFind(TempStringPrefs.styles, "^[ \t]*Pointer:"))
5424 	spliceString(&TempStringPrefs.styles, ptrStyle, "^[ \t]*Regex:");
5425 }
5426 
updatePatternsTo5dot3(void)5427 static void updatePatternsTo5dot3(void)
5428 {
5429     /* This is a bogus function on non-VMS */
5430 #ifdef VMS
5431     const char *psLm5dot2 =
5432         "^[ \t]*PostScript:\\.ps \\.PS \\.eps \\.EPS \\.epsf \\.epsi:\"\\^%!\":::::\"/%\\(\\)\\{\\}\\[\\]\\<\\>\"";
5433 
5434     const char *psLm5dot3 =
5435         "PostScript:.ps .PS .eps .EPS .epsf .EPSF .epsi .EPSI:\"^%!\":::::\"/%(){}[]<>\"";
5436 
5437     /* Upgrade modified language modes, only if the user hasn't
5438        altered the default 5.2 definitions. */
5439     if (regexFind(TempStringPrefs.language, psLm5dot2))
5440 	regexReplace(&TempStringPrefs.language, psLm5dot2, psLm5dot3);
5441 #endif
5442 }
5443 
updatePatternsTo5dot4(void)5444 static void updatePatternsTo5dot4(void)
5445 {
5446 #ifdef VMS
5447     const char *pyLm5dot3 =
5448         "Python:\\.PY:\"\\^#!\\.\\*python\":Auto:None::::?\n";
5449     const char *xrLm5dot3 =
5450         "X Resources:\\.XRESOURCES \\.XDEFAULTS \\.NEDIT:\"\\^\\[!#\\]\\.\\*\\(\\[Aa\\]pp\\|\\[Xx\\]\\)\\.\\*\\[Dd\\]efaults\"::::::?\n";
5451 
5452     const char *pyLm5dot4 =
5453         "Python:.PY:\"^#!.*python\":Auto:None:::\"!\"\"#$%&'()*+,-./:;<=>?@[\\\\]^`{|}~\":\n";
5454     const char *xrLm5dot4 =
5455         "X Resources:.XRESOURCES .XDEFAULTS .NEDIT NEDIT.RC:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n";
5456 #else
5457     const char *pyLm5dot3 =
5458         "Python:\\.py:\"\\^#!\\.\\*python\":Auto:None::::?\n";
5459     const char *xrLm5dot3 =
5460         "X Resources:\\.Xresources \\.Xdefaults \\.nedit:\"\\^\\[!#\\]\\.\\*\\(\\[Aa\\]pp\\|\\[Xx\\]\\)\\.\\*\\[Dd\\]efaults\"::::::?\n";
5461 
5462     const char *pyLm5dot4 =
5463         "Python:.py:\"^#!.*python\":Auto:None:::\"!\"\"#$%&'()*+,-./:;<=>?@[\\\\]^`{|}~\":\n";
5464     const char *xrLm5dot4 =
5465         "X Resources:.Xresources .Xdefaults .nedit nedit.rc:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n";
5466 #endif
5467 
5468     /* Upgrade modified language modes, only if the user hasn't
5469        altered the default 5.3 definitions. */
5470     if (regexFind(TempStringPrefs.language, pyLm5dot3))
5471 	regexReplace(&TempStringPrefs.language, pyLm5dot3, pyLm5dot4);
5472     if (regexFind(TempStringPrefs.language, xrLm5dot3))
5473 	regexReplace(&TempStringPrefs.language, xrLm5dot3, xrLm5dot4);
5474 
5475     /* Add new styles */
5476     if (!regexFind(TempStringPrefs.styles, "^[ \t]*Identifier2:"))
5477 	spliceString(&TempStringPrefs.styles, "Identifier2:SteelBlue:Plain",
5478 		"^[ \t]*Subroutine:");
5479 }
5480 
updatePatternsTo5dot6(void)5481 static void updatePatternsTo5dot6(void)
5482 {
5483     const char *pats[] = {
5484 #ifndef VMS
5485         "Csh:\\.csh \\.cshrc \\.login \\.logout:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\[ \\\\t\\]\\*/bin/csh\"::::::\\n",
5486         "Csh:.csh .cshrc .tcshrc .login .logout:\"^[ \\t]*#[ \\t]*![ \\t]*/bin/t?csh\"::::::\n",
5487 	"LaTeX:\\.tex \\.sty \\.cls \\.ltx \\.ins:::::::\\n",
5488 	"LaTeX:.tex .sty .cls .ltx .ins .clo .fd:::::::\n",
5489         "X Resources:\\.Xresources \\.Xdefaults \\.nedit:\"\\^\\[!#\\]\\.\\*\\(\\[Aa\\]pp\\|\\[Xx\\]\\)\\.\\*\\[Dd\\]efaults\"::::::\\n",
5490         "X Resources:.Xresources .Xdefaults .nedit .pats nedit.rc:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n",
5491 #else
5492 	"Csh:\\.csh \\.cshrc \\.login \\.logout:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\[ \\\\t\\]\\*/bin/csh\"::::::\\n",
5493 	"Csh:.CSH .CSHRC .TCSHRC .LOGIN .LOGOUT:\"^[ \\t]*#[ \\t]*![ \\t]*/bin/t?csh\"::::::\n",
5494 	"LaTeX:\\.TEX \\.STY \\.CLS \\.LTX \\.INS:::::::\\n",
5495 	"LaTeX:.TEX .STY .CLS .LTX .INS .CLO .FD:::::::\n",
5496 	"Lex:\\.lex:::::::\\n",
5497 	"Lex:.LEX:::::::\n",
5498 	"Matlab:\\.m \\.oct \\.sci:::::::\\n",
5499 	"Matlab:.M .OCT .SCI:::::::\n",
5500 	"Regex:\\.reg \\.regex:\"\\\\\\(\\\\\\?\\[:#=!iInN\\]\\.\\+\\\\\\\)\":None:Continuous::::\\n",
5501 	"Regex:.REG .REGEX:\"\\(\\?[:#=!iInN].+\\)\":None:Continuous::::\n",
5502 	"SGML HTML:\\.sgml \\.sgm \\.html \\.htm:\"\\\\\\<\\[Hh\\]\\[Tt\\]\\[Mm\\]\\[Ll\\]\\\\\\>\"::::::\\n",
5503 	"SGML HTML:.SGML .SGM .HTML .HTM:\"\\<[Hh][Tt][Mm][Ll]\\>\"::::::\n",
5504 	"SQL:\\.sql:::::::\\n",
5505 	"SQL:.SQL:::::::\n",
5506 	"Sh Ksh Bash:\\.sh \\.bash \\.ksh \\.profile \\.bashrc \\.bash_logout \\.bash_login \\.bash_profile:\"\\^\\[ \\\\t\\]\\*#\\[ \\\\t\\]\\*!\\[ \\\\t\\]\\*/\\.\\*bin/\\(bash\\|ksh\\|sh\\|zsh\\)\"::::::\\n",
5507 	"Sh Ksh Bash:.SH .BASH .KSH .PROFILE .BASHRC .BASH_LOGOUT .BASH_LOGIN .BASH_PROFILE:\"^[ \\t]*#[ \\t]*![ \\t]*/.*bin/(bash|ksh|sh|zsh)\"::::::\n",
5508 	"XML:\\.xml \\.xsl \\.dtd:\"\\\\\\<\\(\\?i\\\\\\?xml\\|!doctype\\)\"::None:::\"\\<\\>/=\"\"'\\(\\)\\+\\*\\?\\|\":\\n",
5509 	"XML:.XML .XSL .DTD:\"\\<(?i\\?xml|!doctype)\"::None:::\"<>/=\"\"'()+*?|\":\n",
5510 	"X Resources:\\.XRESOURCES \\.XDEFAULTS \\.NEDIT:\"\\^\\[!#\\]\\.\\*\\(\\[Aa\\]pp\\|\\[Xx\\]\\)\\.\\*\\[Dd\\]efaults\"::::::\\n",
5511 	"X Resources:.XRESOURCES .XDEFAULTS .NEDIT .PATS NEDIT.RC:\"^[!#].*([Aa]pp|[Xx]).*[Dd]efaults\"::::::\n",
5512 #endif
5513         NULL };
5514 
5515     /* Upgrade modified language modes, only if the user hasn't
5516        altered the default 5.5 definitions. */
5517     int i;
5518     for (i = 0; pats[i]; i+=2) {
5519         if (regexFind(TempStringPrefs.language, pats[i]))
5520             regexReplace(&TempStringPrefs.language, pats[i], pats[i+1]);
5521     }
5522 
5523     /* Add new styles */
5524     if (!regexFind(TempStringPrefs.styles, "^[ \t]*Bracket:"))
5525 	spliceString(&TempStringPrefs.styles, "Bracket:dark blue:Bold",
5526 		"^[ \t]*Storage Type:");
5527     if (!regexFind(TempStringPrefs.styles, "^[ \t]*Operator:"))
5528 	spliceString(&TempStringPrefs.styles, "Operator:dark blue:Bold",
5529 		"^[ \t]*Bracket:");
5530 }
5531 
5532 
5533 /*
5534  * We migrate a color from the X resources to the prefs if:
5535  *      1.  The prefs entry is equal to the default entry
5536  *      2.  The X resource is not equal to the default entry
5537  */
migrateColor(XrmDatabase prefDB,XrmDatabase appDB,char * class,char * name,int color_index,char * default_val)5538 static void migrateColor(XrmDatabase prefDB, XrmDatabase appDB,
5539         char *class, char *name, int color_index, char *default_val)
5540 {
5541     char *type, *valueString;
5542     XrmValue rsrcValue;
5543 
5544     /* If this color has been customized in the color dialog then use
5545         that value */
5546     if ( strcmp(default_val, PrefData.colorNames[color_index]) )
5547         return;
5548 
5549     /* Retrieve the value of the resource from the DB */
5550     if (XrmGetResource(prefDB, name, class, &type, &rsrcValue)) {
5551         if (strcmp(type, XmRString)) {
5552             fprintf(stderr,"Internal Error: Unexpected resource type, %s\n",
5553                     type);
5554             return;
5555         }
5556         valueString = rsrcValue.addr;
5557     } else if (XrmGetResource(appDB, name, class, &type, &rsrcValue)) {
5558         if (strcmp(type, XmRString)) {
5559             fprintf(stderr,"Internal Error: Unexpected resource type, %s\n",
5560                     type);
5561             return;
5562         }
5563         valueString = rsrcValue.addr;
5564     } else
5565         /* No resources set */
5566         return;
5567 
5568     /* An X resource is set.  If it's non-default, update the prefs. */
5569     if ( strcmp(valueString, default_val) ) {
5570         strncpy(PrefData.colorNames[color_index], valueString,
5571                 MAX_COLOR_LEN);
5572     }
5573 }
5574 
5575 /*
5576  * In 5.4 we moved color preferences from X resources to a color dialog,
5577  * meaning they're in the normal prefs system.  Users who have customized
5578  * their colors with X resources would probably prefer not to have to redo
5579  * the customization in the dialog, so we migrate them to the prefs for them.
5580  */
migrateColorResources(XrmDatabase prefDB,XrmDatabase appDB)5581 static void migrateColorResources(XrmDatabase prefDB, XrmDatabase appDB)
5582 {
5583     migrateColor(prefDB, appDB, APP_CLASS ".Text.Foreground",
5584             APP_NAME ".text.foreground", TEXT_FG_COLOR,
5585             NEDIT_DEFAULT_FG);
5586     migrateColor(prefDB, appDB, APP_CLASS ".Text.Background",
5587             APP_NAME ".text.background", TEXT_BG_COLOR,
5588             NEDIT_DEFAULT_TEXT_BG);
5589     migrateColor(prefDB, appDB, APP_CLASS ".Text.SelectForeground",
5590             APP_NAME ".text.selectForeground", SELECT_FG_COLOR,
5591             NEDIT_DEFAULT_SEL_FG);
5592     migrateColor(prefDB, appDB, APP_CLASS ".Text.SelectBackground",
5593             APP_NAME ".text.selectBackground", SELECT_BG_COLOR,
5594             NEDIT_DEFAULT_SEL_BG);
5595     migrateColor(prefDB, appDB, APP_CLASS ".Text.HighlightForeground",
5596             APP_NAME ".text.highlightForeground", HILITE_FG_COLOR,
5597             NEDIT_DEFAULT_HI_FG);
5598     migrateColor(prefDB, appDB, APP_CLASS ".Text.HighlightBackground",
5599             APP_NAME ".text.highlightBackground", HILITE_BG_COLOR,
5600             NEDIT_DEFAULT_HI_BG);
5601     migrateColor(prefDB, appDB, APP_CLASS ".Text.LineNumForeground",
5602             APP_NAME ".text.lineNumForeground", LINENO_FG_COLOR,
5603             NEDIT_DEFAULT_LINENO_FG);
5604     migrateColor(prefDB, appDB, APP_CLASS ".Text.CursorForeground",
5605             APP_NAME ".text.cursorForeground", CURSOR_FG_COLOR,
5606             NEDIT_DEFAULT_CURSOR_FG);
5607 }
5608 
5609 /*
5610 ** Inserts a string into intoString, reallocating it with nedit_realloc.  If
5611 ** regular expression atExpr is found, inserts the string before atExpr
5612 ** followed by a newline.  If atExpr is not found, inserts insertString
5613 ** at the end, PRECEDED by a newline.
5614 */
spliceString(char ** intoString,const char * insertString,const char * atExpr)5615 static void spliceString(char **intoString, const char *insertString, const char *atExpr)
5616 {
5617     int beginPos, endPos;
5618     int intoLen = strlen(*intoString);
5619     int insertLen = strlen(insertString);
5620     char *newString = (char*)NEditMalloc(intoLen + insertLen + 2);
5621 
5622     if (atExpr != NULL && SearchString(*intoString, atExpr,
5623 	    SEARCH_FORWARD, SEARCH_REGEX, False, 0, &beginPos, &endPos,
5624 	    NULL, NULL, NULL)) {
5625 	strncpy(newString, *intoString, beginPos);
5626     	strncpy(&newString[beginPos], insertString, insertLen);
5627 	newString[beginPos+insertLen] = '\n';
5628 	strncpy(&newString[beginPos+insertLen+1],
5629 		&((*intoString)[beginPos]), intoLen - beginPos);
5630     } else {
5631 	strncpy(newString, *intoString, intoLen);
5632 	newString[intoLen] = '\n';
5633 	strncpy(&newString[intoLen+1], insertString, insertLen);
5634     }
5635     newString[intoLen + insertLen + 1] = '\0';
5636     NEditFree(*intoString);
5637     *intoString = newString;
5638 }
5639 
5640 /*
5641 ** Simplified regular expression search routine which just returns true
5642 ** or false depending on whether inString matches expr
5643 */
regexFind(const char * inString,const char * expr)5644 static int regexFind(const char *inString, const char *expr)
5645 {
5646     int beginPos, endPos;
5647     return SearchString(inString, expr, SEARCH_FORWARD, SEARCH_REGEX, False,
5648 	    0, &beginPos, &endPos, NULL, NULL, NULL);
5649 }
5650 
5651 /*
5652 ** Simplified case-sensisitive string search routine which just
5653 ** returns true or false depending on whether inString matches expr
5654 */
caseFind(const char * inString,const char * expr)5655 static int caseFind(const char *inString, const char *expr)
5656 {
5657     int beginPos, endPos;
5658     return SearchString(inString, expr, SEARCH_FORWARD, SEARCH_CASE_SENSE,
5659             False, 0, &beginPos, &endPos, NULL, NULL, NULL);
5660 }
5661 
5662 /*
5663 ** Common implementation for simplified string replacement routines.
5664 */
stringReplace(char ** inString,const char * expr,const char * replaceWith,int searchType,int replaceLen)5665 static int stringReplace(char **inString, const char *expr,
5666                          const char *replaceWith, int searchType,
5667 			 int replaceLen)
5668 {
5669     int beginPos, endPos, newLen;
5670     char *newString;
5671     int inLen = strlen(*inString);
5672     if (0 >= replaceLen) replaceLen = strlen(replaceWith);
5673     if (!SearchString(*inString, expr, SEARCH_FORWARD, searchType, False,
5674 	    0, &beginPos, &endPos, NULL, NULL, NULL))
5675 	return FALSE;
5676     newLen = inLen + replaceLen - (endPos-beginPos);
5677     newString = (char*)NEditMalloc(newLen + 1);
5678     strncpy(newString, *inString, beginPos);
5679     strncpy(&newString[beginPos], replaceWith, replaceLen);
5680     strncpy(&newString[beginPos+replaceLen],
5681 	    &((*inString)[endPos]), inLen - endPos);
5682     newString[newLen] = '\0';
5683     NEditFree(*inString);
5684     *inString = newString;
5685     return TRUE;
5686 }
5687 
5688 /*
5689 ** Simplified regular expression replacement routine which replaces the
5690 ** first occurence of expr in inString with replaceWith, reallocating
5691 ** inString with NEditMalloc.  If expr is not found, does nothing and
5692 ** returns false.
5693 */
regexReplace(char ** inString,const char * expr,const char * replaceWith)5694 static int regexReplace(char **inString, const char *expr,
5695                         const char *replaceWith)
5696 {
5697     return stringReplace(inString, expr, replaceWith, SEARCH_REGEX, -1);
5698 }
5699 
5700 /*
5701 ** Simplified case-sensisitive string replacement routine which
5702 ** replaces the first occurence of expr in inString with replaceWith,
5703 ** reallocating inString with NEditMalloc.  If expr is not found, does nothing
5704 ** and returns false.
5705 */
caseReplace(char ** inString,const char * expr,const char * replaceWith,int replaceLen)5706 static int caseReplace(char **inString, const char *expr,
5707                        const char *replaceWith, int replaceLen)
5708 {
5709     return stringReplace(inString, expr, replaceWith, SEARCH_CASE_SENSE,
5710                          replaceLen);
5711 }
5712 
5713 /*
5714 ** Looks for a (case-sensitive literal) match of an old macro text in a
5715 ** temporary macro commands buffer. If the text is found, it is replaced by
5716 ** a substring of the default macros, bounded by a given start and end pattern
5717 ** (inclusive). Returns the length of the replacement.
5718 */
replaceMacroIfUnchanged(const char * oldText,const char * newStart,const char * newEnd)5719 static int replaceMacroIfUnchanged(const char* oldText, const char* newStart,
5720                                    const char* newEnd)
5721 {
5722     if (caseFind(TempStringPrefs.macroCmds, oldText)) {
5723 #ifdef VMS
5724         const char *start = strstr(PrefDescrip[1].defaultString, newStart);
5725 #else
5726         const char *start = strstr(PrefDescrip[2].defaultString, newStart);
5727 #endif
5728 	if (start) {
5729             const char *end = strstr(start, newEnd);
5730             if (end) {
5731                 int length = (int)(end-start) + strlen(newEnd);
5732                 caseReplace(&TempStringPrefs.macroCmds, oldText, start, length);
5733                 return length;
5734             }
5735 	}
5736     }
5737     return 0;
5738 }
5739 
5740 #ifndef VMS
5741 /*
5742 ** Replace all '#' characters in shell commands by '##' to keep commands
5743 ** containing those working. '#' is a line number placeholder in 5.3 and
5744 ** had no special meaning before.
5745 */
updateShellCmdsTo5dot3(void)5746 static void updateShellCmdsTo5dot3(void)
5747 {
5748     char *cOld, *cNew, *pCol, *pNL;
5749     int  nHash, isCmd;
5750     char *newString;
5751 
5752     if(!TempStringPrefs.shellCmds)
5753 	return;
5754 
5755     /* Count number of '#'. If there are '#' characters in the non-command
5756     ** part of the definition we count too much and later allocate too much
5757     ** memory for the new string, but this doesn't hurt.
5758     */
5759     for(cOld=TempStringPrefs.shellCmds, nHash=0; *cOld; cOld++)
5760 	if(*cOld == '#')
5761 	    nHash++;
5762 
5763     /* No '#' -> no conversion necessary. */
5764     if(!nHash)
5765 	return;
5766 
5767     newString=(char*)NEditMalloc(strlen(TempStringPrefs.shellCmds) + 1 + nHash);
5768 
5769     cOld  = TempStringPrefs.shellCmds;
5770     cNew  = newString;
5771     isCmd = 0;
5772     pCol  = NULL;
5773     pNL   = NULL;
5774 
5775     /* Copy all characters from TempStringPrefs.shellCmds into newString
5776     ** and duplicate '#' in command parts. A simple check for really beeing
5777     ** inside a command part (starting with '\n', between the the two last
5778     ** '\n' a colon ':' must have been found) is preformed.
5779     */
5780     while(*cOld) {
5781 	/* actually every 2nd line is a command. We additionally
5782 	** check if there is a colon ':' in the previous line.
5783 	*/
5784 	if(*cOld=='\n') {
5785 	    if((pCol > pNL) && !isCmd)
5786 	      	isCmd=1;
5787 	    else
5788 	      	isCmd=0;
5789 	    pNL=cOld;
5790 	}
5791 
5792 	if(!isCmd && *cOld ==':')
5793 	    pCol = cOld;
5794 
5795 	/* Duplicate hashes if we're in a command part */
5796 	if(isCmd && *cOld=='#')
5797 	    *cNew++ = '#';
5798 
5799 	/* Copy every character */
5800 	*cNew++ = *cOld++;
5801 
5802     }
5803 
5804     /* Terminate new preferences string */
5805     *cNew = 0;
5806 
5807     /* free the old memory */
5808     NEditFree(TempStringPrefs.shellCmds);
5809 
5810     /* exchange the string */
5811     TempStringPrefs.shellCmds = newString;
5812 
5813 }
5814 
5815 #else
5816 
updateShellCmdsTo5dot3(void)5817 static void updateShellCmdsTo5dot3(void) {
5818     /* No shell commands in VMS ! */
5819     return;
5820 }
5821 
5822 #endif
5823 
updateShellCmdsTo5dot4(void)5824 static void updateShellCmdsTo5dot4(void)
5825 {
5826 #ifndef VMS /* No shell commands on VMS */
5827 
5828 #ifdef __FreeBSD__
5829     const char* wc5dot3 =
5830       "^(\\s*)set wc=`wc`; echo \\$wc\\[1\\] \"words,\" \\$wc\\[2\\] \"lines,\" \\$wc\\[3\\] \"characters\"\\n";
5831     const char* wc5dot4 =
5832       "wc | awk '{print $2 \" lines, \" $1 \" words, \" $3 \" characters\"}'\n";
5833 #else
5834     const char* wc5dot3 =
5835       "^(\\s*)set wc=`wc`; echo \\$wc\\[1\\] \"lines,\" \\$wc\\[2\\] \"words,\" \\$wc\\[3\\] \"characters\"\\n";
5836     const char* wc5dot4 =
5837       "wc | awk '{print $1 \" lines, \" $2 \" words, \" $3 \" characters\"}'\n";
5838 #endif /* __FreeBSD__ */
5839 
5840     if (regexFind(TempStringPrefs.shellCmds, wc5dot3))
5841 	regexReplace(&TempStringPrefs.shellCmds, wc5dot3, wc5dot4);
5842 
5843 #endif /* VMS */
5844 
5845     return;
5846 }
5847 
updateMacroCmdsTo5dot5(void)5848 static void updateMacroCmdsTo5dot5(void)
5849 {
5850     const char* uc5dot4 =
5851       "^(\\s*)if \\(substring\\(sel, keepEnd - 1, keepEnd == \" \"\\)\\)\\n";
5852     const char* uc5dot5 =
5853       "		if (substring(sel, keepEnd - 1, keepEnd) == \" \")\n";
5854     if (regexFind(TempStringPrefs.macroCmds, uc5dot4))
5855 	regexReplace(&TempStringPrefs.macroCmds, uc5dot4, uc5dot5);
5856 
5857     return;
5858 }
5859 
updateMacroCmdsTo5dot6(void)5860 static void updateMacroCmdsTo5dot6(void)
5861 {
5862     /*
5863        This is ridiculous. Macros don't belong in the default preferences
5864        string.
5865        This code is also likely to break when the macro commands are upgraded
5866        again in a next release, because it looks for patterns in the default
5867        macro string (which may change).
5868        Using a "Default" mechanism, like we do for highlighting patterns
5869        would simplify upgrading A LOT in the future, but changing the way
5870        default macros are stored, is a lot of work too, unfortunately.
5871     */
5872     const char *pats[] = {
5873         "Complete Word:Alt+D::: {\n\
5874 		# Tuning parameters\n\
5875 		ScanDistance = 200\n\
5876 		\n\
5877 		# Search back to a word boundary to find the word to complete\n\
5878 		startScan = max(0, $cursor - ScanDistance)\n\
5879 		endScan = min($text_length, $cursor + ScanDistance)\n\
5880 		scanString = get_range(startScan, endScan)\n\
5881 		keyEnd = $cursor-startScan\n\
5882 		keyStart = search_string(scanString, \"<\", keyEnd, \"backward\", \"regex\")\n\
5883 		if (keyStart == -1)\n\
5884 		    return\n\
5885 		keyString = \"<\" substring(scanString, keyStart, keyEnd)\n\
5886 		\n\
5887 		# search both forward and backward from the cursor position.  Note that\n\
5888 		# using a regex search can lead to incorrect results if any of the special\n\
5889 		# regex characters is encountered, which is not considered a delimiter\n\
5890 		backwardSearchResult = search_string(scanString, keyString, keyStart-1, \\\n\
5891 		    	\"backward\", \"regex\")\n\
5892 		forwardSearchResult = search_string(scanString, keyString, keyEnd, \"regex\")\n\
5893 		if (backwardSearchResult == -1 && forwardSearchResult == -1) {\n\
5894 		    beep()\n\
5895 		    return\n\
5896 		}\n\
5897 		\n\
5898 		# if only one direction matched, use that, otherwise use the nearest\n\
5899 		if (backwardSearchResult == -1)\n\
5900 		    matchStart = forwardSearchResult\n\
5901 		else if (forwardSearchResult == -1)\n\
5902 		    matchStart = backwardSearchResult\n\
5903 		else {\n\
5904 		    if (keyStart - backwardSearchResult <= forwardSearchResult - keyEnd)\n\
5905 		    	matchStart = backwardSearchResult\n\
5906 		    else\n\
5907 		    	matchStart = forwardSearchResult\n\
5908 		}\n\
5909 		\n\
5910 		# find the complete word\n\
5911 		matchEnd = search_string(scanString, \">\", matchStart, \"regex\")\n\
5912 		completedWord = substring(scanString, matchStart, matchEnd)\n\
5913 		\n\
5914 		# replace it in the window\n\
5915 		replace_range(startScan + keyStart, $cursor, completedWord)\n\
5916 	}", "Complete Word:", "\n\t}",
5917         "Fill Sel. w/Char:::R: {\n\
5918 		if ($selection_start == -1) {\n\
5919 		    beep()\n\
5920 		    return\n\
5921 		}\n\
5922 		\n\
5923 		# Ask the user what character to fill with\n\
5924 		fillChar = string_dialog(\"Fill selection with what character?\", \"OK\", \"Cancel\")\n\
5925 		if ($string_dialog_button == 2 || $string_dialog_button == 0)\n\
5926 		    return\n\
5927 		\n\
5928 		# Count the number of lines in the selection\n\
5929 		nLines = 0\n\
5930 		for (i=$selection_start; i<$selection_end; i++)\n\
5931 		    if (get_character(i) == \"\\n\")\n\
5932 		    	nLines++\n\
5933 		\n\
5934 		# Create the fill text\n\
5935 		rectangular = $selection_left != -1\n\
5936 		line = \"\"\n\
5937 		fillText = \"\"\n\
5938 		if (rectangular) {\n\
5939 		    for (i=0; i<$selection_right-$selection_left; i++)\n\
5940 			line = line fillChar\n\
5941 		    for (i=0; i<nLines; i++)\n\
5942 			fillText = fillText line \"\\n\"\n\
5943 		    fillText = fillText line\n\
5944 		} else {\n\
5945 		    if (nLines == 0) {\n\
5946 		    	for (i=$selection_start; i<$selection_end; i++)\n\
5947 		    	    fillText = fillText fillChar\n\
5948 		    } else {\n\
5949 		    	startIndent = 0\n\
5950 		    	for (i=$selection_start-1; i>=0 && get_character(i)!=\"\\n\"; i--)\n\
5951 		    	    startIndent++\n\
5952 		    	for (i=0; i<$wrap_margin-startIndent; i++)\n\
5953 		    	    fillText = fillText fillChar\n\
5954 		    	fillText = fillText \"\\n\"\n\
5955 			for (i=0; i<$wrap_margin; i++)\n\
5956 			    line = line fillChar\n\
5957 			for (i=0; i<nLines-1; i++)\n\
5958 			    fillText = fillText line \"\\n\"\n\
5959 			for (i=$selection_end-1; i>=$selection_start && get_character(i)!=\"\\n\"; \\\n\
5960 			    	i--)\n\
5961 			    fillText = fillText fillChar\n\
5962 		    }\n\
5963 		}\n\
5964 		\n\
5965 		# Replace the selection with the fill text\n\
5966 		replace_selection(fillText)\n\
5967 	}", "Fill Sel. w/Char:", "\n\t}",
5968         "Comments>/* Uncomment */@C@C++@Java@CSS@JavaScript@Lex:::R: {\n\
5969 		sel = get_selection()\n\
5970 		selStart = $selection_start\n\
5971 		selEnd = $selection_end\n\
5972 		commentStart = search_string(sel, \"/*\", 0)\n\
5973 		if (substring(sel, commentStart + 2, commentStart + 3) == \" \")\n\
5974 		    keepStart = commentStart + 3\n\
5975 		else\n\
5976 		    keepStart = commentStart + 2\n\
5977 		keepEnd = search_string(sel, \"*/\", length(sel), \"backward\")\n\
5978 		commentEnd = keepEnd + 2\n\
5979 		if (substring(sel, keepEnd - 1, keepEnd) == \" \")\n\
5980 		    keepEnd = keepEnd - 1\n\
5981 		replace_range(selStart + commentStart, selStart + commentEnd, \\\n\
5982 			substring(sel, keepStart, keepEnd))\n\
5983 		select(selStart, selEnd - (keepStart-commentStart) - \\\n\
5984 			(commentEnd - keepEnd))\n\
5985 	}", "Comments>/* Uncomment */", "\n\t}",
5986         "Comments>Bar Uncomment@C:::R: {\n\
5987 		selStart = $selection_start\n\
5988 		selEnd = $selection_end\n\
5989 		newText = get_range(selStart+3, selEnd-4)\n\
5990 		newText = replace_in_string(newText, \"^ \\\\* \", \"\", \"regex\")\n\
5991 		replace_range(selStart, selEnd, newText)\n\
5992 		select(selStart, selStart + length(newText))\n\
5993 	}","Comments>Bar Uncomment@C:", "\n\t}",
5994         "Make C Prototypes@C@C++:::: {\n\
5995 		if ($selection_start == -1) {\n\
5996 		    start = 0\n\
5997 		    end = $text_length\n\
5998 		} else {\n\
5999 		    start = $selection_start\n\
6000 		    end = $selection_end\n\
6001 		}\n\
6002 		string = get_range(start, end)\n\
6003 		nDefs = 0", "Make C Prototypes@C@C++:", "\t\tnDefs = 0",
6004         NULL };
6005     int i;
6006     for (i = 0; pats[i]; i+=3)
6007         replaceMacroIfUnchanged(pats[i], pats[i+1], pats[i+2]);
6008     return;
6009 }
6010 
6011 #ifdef SGI_CUSTOM
6012 /*
6013 ** Present the user a dialog for specifying whether or not a short
6014 ** menu mode preference should be applied toward the default setting.
6015 ** Return False (function value) if operation was canceled, return True
6016 ** in setDefault if requested to reset the default value.
6017 */
shortPrefToDefault(Widget parent,const char * settingName,int * setDefault)6018 static int shortPrefToDefault(Widget parent, const char *settingName, int *setDefault)
6019 {
6020     char msg[100] = "";
6021 
6022     if (!GetPrefShortMenus()) {
6023         *setDefault = False;
6024         return True;
6025     }
6026 
6027     sprintf(msg, "%s\nSave as default for future windows as well?", settingName);
6028     switch (DialogF (DF_QUES, parent, 3, "Save Default", msg, "Yes", "No",
6029             "Cancel"))
6030     {
6031         case 1: /* yes */
6032             *setDefault = True;
6033             return True;
6034         case 2: /* no */
6035             *setDefault = False;
6036             return True;
6037         case 3: /* cancel */
6038             return False;
6039     }
6040     return False; /* not reached */
6041 }
6042 #endif
6043 
6044 /* Decref the default calltips file(s) for this window */
UnloadLanguageModeTipsFile(WindowInfo * window)6045 void UnloadLanguageModeTipsFile(WindowInfo *window)
6046 {
6047     int mode;
6048 
6049     mode = window->languageMode;
6050     if (mode != PLAIN_LANGUAGE_MODE && LanguageModes[mode]->defTipsFile) {
6051         DeleteTagsFile( LanguageModes[mode]->defTipsFile, TIP, False );
6052     }
6053 }
6054 
6055 /******************************************************************************
6056  * The Color selection dialog
6057  ******************************************************************************/
6058 
6059 /*
6060 There are 8 colors:   And 8 indices:
6061 textFg                TEXT_FG_COLOR
6062 textBg                TEXT_BG_COLOR
6063 selectFg              SELECT_FG_COLOR
6064 selectBg              SELECT_BG_COLOR
6065 hiliteFg              HILITE_FG_COLOR
6066 hiliteBg              HILITE_BG_COLOR
6067 lineNoFg              LINENO_FG_COLOR
6068 cursorFg              CURSOR_FG_COLOR
6069 */
6070 
6071 #define MARGIN_SPACING 10
6072 
6073 /*
6074  * Callbacks for field modifications
6075  */
textFgModifiedCB(Widget w,XtPointer clientData,XtPointer callData)6076 static void textFgModifiedCB(Widget w, XtPointer clientData,
6077       XtPointer callData)
6078 {
6079     colorDialog *cd = (colorDialog *)clientData;
6080     showColorStatus(cd, cd->textFgW, cd->textFgErrW);
6081 }
6082 
textBgModifiedCB(Widget w,XtPointer clientData,XtPointer callData)6083 static void textBgModifiedCB(Widget w, XtPointer clientData,
6084       XtPointer callData)
6085 {
6086     colorDialog *cd = (colorDialog *)clientData;
6087     showColorStatus(cd, cd->textBgW, cd->textBgErrW);
6088 }
6089 
selectFgModifiedCB(Widget w,XtPointer clientData,XtPointer callData)6090 static void selectFgModifiedCB(Widget w, XtPointer clientData,
6091         XtPointer callData)
6092 {
6093     colorDialog *cd = (colorDialog *)clientData;
6094     showColorStatus(cd, cd->selectFgW, cd->selectFgErrW);
6095 }
6096 
selectBgModifiedCB(Widget w,XtPointer clientData,XtPointer callData)6097 static void selectBgModifiedCB(Widget w, XtPointer clientData,
6098         XtPointer callData)
6099 {
6100     colorDialog *cd = (colorDialog *)clientData;
6101     showColorStatus(cd, cd->selectBgW, cd->selectBgErrW);
6102 }
6103 
hiliteFgModifiedCB(Widget w,XtPointer clientData,XtPointer callData)6104 static void hiliteFgModifiedCB(Widget w, XtPointer clientData,
6105         XtPointer callData)
6106 {
6107     colorDialog *cd = (colorDialog *)clientData;
6108     showColorStatus(cd, cd->hiliteFgW, cd->hiliteFgErrW);
6109 }
6110 
hiliteBgModifiedCB(Widget w,XtPointer clientData,XtPointer callData)6111 static void hiliteBgModifiedCB(Widget w, XtPointer clientData,
6112         XtPointer callData)
6113 {
6114     colorDialog *cd = (colorDialog *)clientData;
6115     showColorStatus(cd, cd->hiliteBgW, cd->hiliteBgErrW);
6116 }
6117 
lineNoFgModifiedCB(Widget w,XtPointer clientData,XtPointer callData)6118 static void lineNoFgModifiedCB(Widget w, XtPointer clientData,
6119         XtPointer callData)
6120 {
6121     colorDialog *cd = (colorDialog *)clientData;
6122     showColorStatus(cd, cd->lineNoFgW, cd->lineNoFgErrW);
6123 }
6124 
cursorFgModifiedCB(Widget w,XtPointer clientData,XtPointer callData)6125 static void cursorFgModifiedCB(Widget w, XtPointer clientData,
6126         XtPointer callData)
6127 {
6128     colorDialog *cd = (colorDialog *)clientData;
6129     showColorStatus(cd, cd->cursorFgW, cd->cursorFgErrW);
6130 }
6131 
6132 
6133 /*
6134  * Helper functions for validating colors
6135  */
verifyAllColors(colorDialog * cd)6136 static int verifyAllColors(colorDialog *cd)
6137 {
6138     /* Maybe just check for empty strings in error widgets instead? */
6139     return (checkColorStatus(cd, cd->textFgW) &&
6140             checkColorStatus(cd, cd->textBgW) &&
6141             checkColorStatus(cd, cd->selectFgW) &&
6142             checkColorStatus(cd, cd->selectBgW) &&
6143             checkColorStatus(cd, cd->hiliteFgW) &&
6144             checkColorStatus(cd, cd->hiliteBgW) &&
6145             checkColorStatus(cd, cd->lineNoFgW) &&
6146             checkColorStatus(cd, cd->cursorFgW) );
6147 }
6148 
6149 /* Returns True if the color is valid, False if it's not */
checkColorStatus(colorDialog * cd,Widget colorFieldW)6150 static Boolean checkColorStatus(colorDialog *cd, Widget colorFieldW)
6151 {
6152     Colormap cMap;
6153     XColor colorDef;
6154     Status status;
6155     Display *display = XtDisplay(cd->shell);
6156     char *text = XmTextGetString(colorFieldW);
6157     XtVaGetValues(cd->shell, XtNcolormap, &cMap, NULL);
6158     status = XParseColor(display, cMap, text, &colorDef);
6159     NEditFree(text);
6160     return (status != 0);
6161 }
6162 
6163 /* Show or hide errorLabelW depending on whether or not colorFieldW
6164     contains a valid color name. */
showColorStatus(colorDialog * cd,Widget colorFieldW,Widget errorLabelW)6165 static void showColorStatus(colorDialog *cd, Widget colorFieldW,
6166         Widget errorLabelW)
6167 {
6168     /* Should set the OK/Apply button sensitivity here, instead
6169        of leaving is sensitive and then complaining if an error. */
6170     XtSetMappedWhenManaged( errorLabelW, !checkColorStatus(cd, colorFieldW) );
6171 }
6172 
6173 /* Update the colors in the window or in the preferences */
updateColors(colorDialog * cd)6174 static void updateColors(colorDialog *cd)
6175 {
6176     WindowInfo *window;
6177 
6178     char    *textFg = XmTextGetString(cd->textFgW),
6179             *textBg = XmTextGetString(cd->textBgW),
6180             *selectFg = XmTextGetString(cd->selectFgW),
6181             *selectBg = XmTextGetString(cd->selectBgW),
6182             *hiliteFg = XmTextGetString(cd->hiliteFgW),
6183             *hiliteBg = XmTextGetString(cd->hiliteBgW),
6184             *lineNoFg = XmTextGetString(cd->lineNoFgW),
6185             *cursorFg = XmTextGetString(cd->cursorFgW);
6186 
6187     for (window = WindowList; window != NULL; window = window->next)
6188     {
6189         SetColors(window, textFg, textBg, selectFg, selectBg, hiliteFg,
6190                 hiliteBg, lineNoFg, cursorFg);
6191     }
6192 
6193     SetPrefColorName(TEXT_FG_COLOR  , textFg  );
6194     SetPrefColorName(TEXT_BG_COLOR  , textBg  );
6195     SetPrefColorName(SELECT_FG_COLOR, selectFg);
6196     SetPrefColorName(SELECT_BG_COLOR, selectBg);
6197     SetPrefColorName(HILITE_FG_COLOR, hiliteFg);
6198     SetPrefColorName(HILITE_BG_COLOR, hiliteBg);
6199     SetPrefColorName(LINENO_FG_COLOR, lineNoFg);
6200     SetPrefColorName(CURSOR_FG_COLOR, cursorFg);
6201 
6202     NEditFree(textFg);
6203     NEditFree(textBg);
6204     NEditFree(selectFg);
6205     NEditFree(selectBg);
6206     NEditFree(hiliteFg);
6207     NEditFree(hiliteBg);
6208     NEditFree(lineNoFg);
6209     NEditFree(cursorFg);
6210 }
6211 
6212 
6213 /*
6214  * Dialog button callbacks
6215  */
6216 
colorDestroyCB(Widget w,XtPointer clientData,XtPointer callData)6217 static void colorDestroyCB(Widget w, XtPointer clientData, XtPointer callData)
6218 {
6219     colorDialog *cd = (colorDialog *)clientData;
6220 
6221     cd->window->colorDialog = NULL;
6222     NEditFree(cd);
6223 }
6224 
colorOkCB(Widget w,XtPointer clientData,XtPointer callData)6225 static void colorOkCB(Widget w, XtPointer clientData, XtPointer callData)
6226 {
6227     colorDialog *cd = (colorDialog *)clientData;
6228 
6229     if(!verifyAllColors(cd))
6230     {
6231         DialogF(DF_ERR, w, 1, "Invalid Colors",
6232                 "All colors must be valid to proceed.", "OK");
6233         return;
6234     }
6235     updateColors(cd);
6236 
6237     /* pop down and destroy the dialog */
6238     XtDestroyWidget(cd->shell);
6239 }
6240 
colorApplyCB(Widget w,XtPointer clientData,XtPointer callData)6241 static void colorApplyCB(Widget w, XtPointer clientData, XtPointer callData)
6242 {
6243     colorDialog *cd = (colorDialog *)clientData;
6244 
6245     if(!verifyAllColors(cd))
6246     {
6247         DialogF(DF_ERR, w, 1, "Invalid Colors",
6248                 "All colors must be valid to be applied.", "OK");
6249         return;
6250     }
6251     updateColors(cd);
6252 }
6253 
colorCloseCB(Widget w,XtPointer clientData,XtPointer callData)6254 static void colorCloseCB(Widget w, XtPointer clientData, XtPointer callData)
6255 {
6256     colorDialog *cd = (colorDialog *)clientData;
6257 
6258     /* pop down and destroy the dialog */
6259     XtDestroyWidget(cd->shell);
6260 }
6261 
6262 
6263 /* Add a label, error label, and text entry label with a validation
6264     callback */
addColorGroup(Widget parent,const char * name,char mnemonic,char * label,Widget * fieldW,Widget * errW,Widget topWidget,int leftPos,int rightPos,XtCallbackProc modCallback,colorDialog * cd)6265 static Widget addColorGroup( Widget parent, const char *name, char mnemonic,
6266         char *label, Widget *fieldW, Widget *errW, Widget topWidget,
6267         int leftPos, int rightPos, XtCallbackProc modCallback,
6268         colorDialog *cd )
6269 {
6270     Widget lblW;
6271     char *longerName;
6272     XmString s1;
6273     int nameLen = strlen(name);
6274 
6275     /* The label widget */
6276     longerName = (char*)NEditMalloc(nameLen+7);
6277     strcpy(longerName, name);
6278     strcat(longerName, "Lbl");
6279     lblW = XtVaCreateManagedWidget(longerName,
6280           xmLabelGadgetClass, parent,
6281           XmNlabelString, s1=XmStringCreateSimple( label ),
6282           XmNmnemonic, mnemonic,
6283           XmNtopAttachment, XmATTACH_WIDGET,
6284           XmNtopWidget, topWidget,
6285           XmNtopOffset, MARGIN_SPACING,
6286           XmNleftAttachment, XmATTACH_POSITION,
6287           XmNleftPosition, leftPos, NULL);
6288     XmStringFree(s1);
6289 
6290     /* The error label widget */
6291     strcpy(&(longerName[nameLen]), "ErrLbl");
6292     *errW = XtVaCreateManagedWidget(longerName,
6293           xmLabelWidgetClass, parent,
6294           XmNlabelString, s1=XmStringCreateSimple("(Invalid!)"),
6295           XmNalignment, XmALIGNMENT_END,
6296           XmNtopAttachment, XmATTACH_WIDGET,
6297           XmNtopWidget, topWidget,
6298           XmNtopOffset, MARGIN_SPACING,
6299           XmNleftAttachment, XmATTACH_WIDGET,
6300           XmNleftWidget, lblW,
6301           XmNrightAttachment, XmATTACH_POSITION,
6302           XmNrightPosition, rightPos, NULL);
6303     XmStringFree(s1);
6304 
6305     /* The text field entry widget */
6306     *fieldW = XtVaCreateManagedWidget(name, xmTextWidgetClass,
6307           parent,
6308           XmNcolumns, MAX_COLOR_LEN-1,
6309           XmNmaxLength, MAX_COLOR_LEN-1,
6310           XmNleftAttachment, XmATTACH_POSITION,
6311           XmNleftPosition, leftPos,
6312           XmNrightAttachment, XmATTACH_POSITION,
6313           XmNrightPosition, rightPos,
6314           XmNtopAttachment, XmATTACH_WIDGET,
6315           XmNtopWidget, lblW, NULL);
6316     RemapDeleteKey(*fieldW);
6317     XtAddCallback(*fieldW, XmNvalueChangedCallback,
6318           modCallback, cd);
6319     XtVaSetValues(lblW, XmNuserData, *fieldW, NULL);
6320 
6321     NEditFree(longerName);
6322     return *fieldW;
6323 }
6324 
6325 
6326 /*
6327  * Code for the dialog itself
6328  */
ChooseColors(WindowInfo * window)6329 void ChooseColors(WindowInfo *window)
6330 {
6331     Widget form, tmpW, topW, infoLbl;
6332     Widget okBtn, applyBtn, closeBtn;
6333     colorDialog *cd;
6334     XmString s1;
6335     int ac;
6336     Arg args[20];
6337 
6338     /* if the dialog is already displayed, just pop it to the top and return */
6339     if (window->colorDialog != NULL) {
6340       RaiseDialogWindow(((colorDialog *)window->colorDialog)->shell);
6341       return;
6342     }
6343 
6344     /* Create a structure for keeping track of dialog state */
6345     cd = NEditNew(colorDialog);
6346     window->colorDialog = (void*)cd;
6347 
6348     /* Create a form widget in a dialog shell */
6349     ac = 0;
6350     XtSetArg(args[ac], XmNautoUnmanage, False); ac++;
6351     XtSetArg(args[ac], XmNresizePolicy, XmRESIZE_NONE); ac++;
6352     form = CreateFormDialog(window->shell, "choose colors", args, ac);
6353     XtVaSetValues(form, XmNshadowThickness, 0, NULL);
6354     cd->shell = XtParent(form);
6355     cd->window = window;
6356     XtVaSetValues(cd->shell, XmNtitle, "Colors", NULL);
6357     AddMotifCloseCallback(XtParent(form), colorCloseCB, cd);
6358     XtAddCallback(form, XmNdestroyCallback, colorDestroyCB, cd);
6359 
6360     /* Information label */
6361     infoLbl = XtVaCreateManagedWidget("infoLbl",
6362             xmLabelGadgetClass, form,
6363             XmNtopAttachment, XmATTACH_POSITION,
6364             XmNtopPosition, 2,
6365             XmNleftAttachment, XmATTACH_POSITION,
6366             XmNleftPosition, 1,
6367             XmNrightAttachment, XmATTACH_POSITION,
6368             XmNrightPosition, 99,
6369             XmNalignment, XmALIGNMENT_CENTER,
6370             XmNlabelString, s1 = XmStringCreateLtoR(
6371                 "Colors can be entered as names (e.g. red, blue) or "
6372                 "as RGB triples\nin the format #RRGGBB, where each digit "
6373                 "is in the range 0-f.", XmFONTLIST_DEFAULT_TAG),
6374             NULL);
6375     XmStringFree(s1);
6376 
6377     topW = infoLbl;
6378 
6379     /* The left column (foregrounds) of color entry groups */
6380     tmpW = addColorGroup( form, "textFg", 'P', "Plain Text Foreground",
6381             &(cd->textFgW), &(cd->textFgErrW), topW, 1, 49,
6382             textFgModifiedCB, cd );
6383     tmpW = addColorGroup( form, "selectFg", 'S', "Selection Foreground",
6384             &(cd->selectFgW), &(cd->selectFgErrW), tmpW, 1, 49,
6385             selectFgModifiedCB, cd );
6386     tmpW = addColorGroup( form, "hiliteFg", 'M', "Matching (..) Foreground",
6387             &(cd->hiliteFgW), &(cd->hiliteFgErrW), tmpW, 1, 49,
6388             hiliteFgModifiedCB, cd );
6389     tmpW = addColorGroup( form, "lineNoFg", 'L', "Line Numbers",
6390             &(cd->lineNoFgW), &(cd->lineNoFgErrW), tmpW, 1, 49,
6391             lineNoFgModifiedCB, cd );
6392 
6393     /* The right column (backgrounds) */
6394     tmpW = addColorGroup( form, "textBg", 'T', "Text Area Background",
6395             &(cd->textBgW), &(cd->textBgErrW), topW, 51, 99,
6396             textBgModifiedCB, cd );
6397     tmpW = addColorGroup( form, "selectBg", 'B', "Selection Background",
6398             &(cd->selectBgW), &(cd->selectBgErrW), tmpW, 51, 99,
6399             selectBgModifiedCB, cd );
6400     tmpW = addColorGroup( form, "hiliteBg", 'h', "Matching (..) Background",
6401             &(cd->hiliteBgW), &(cd->hiliteBgErrW), tmpW, 51, 99,
6402             hiliteBgModifiedCB, cd );
6403     tmpW = addColorGroup( form, "cursorFg", 'C', "Cursor Color",
6404             &(cd->cursorFgW), &(cd->cursorFgErrW), tmpW, 51, 99,
6405             cursorFgModifiedCB, cd );
6406 
6407     tmpW = XtVaCreateManagedWidget("infoLbl",
6408             xmLabelGadgetClass, form,
6409             XmNtopAttachment, XmATTACH_WIDGET,
6410             XmNtopWidget, tmpW,
6411             XmNtopOffset, MARGIN_SPACING,
6412             XmNleftAttachment, XmATTACH_POSITION,
6413             XmNleftPosition, 1,
6414             XmNrightAttachment, XmATTACH_POSITION,
6415             XmNrightPosition, 99,
6416             XmNalignment, XmALIGNMENT_CENTER,
6417             XmNlabelString, s1 = XmStringCreateLtoR(
6418                 "NOTE: Foreground colors only apply when syntax highlighting "
6419                 "is DISABLED.\n", XmFONTLIST_DEFAULT_TAG),
6420             NULL);
6421     XmStringFree(s1);
6422 
6423     tmpW = XtVaCreateManagedWidget("sep",
6424             xmSeparatorGadgetClass, form,
6425             XmNtopAttachment, XmATTACH_WIDGET,
6426             XmNtopWidget, tmpW,
6427             XmNleftAttachment, XmATTACH_FORM,
6428             XmNrightAttachment, XmATTACH_FORM, NULL);
6429 
6430     /* The OK, Apply, and Cancel buttons */
6431     okBtn = XtVaCreateManagedWidget("ok",
6432             xmPushButtonWidgetClass, form,
6433             XmNlabelString, s1=XmStringCreateSimple("OK"),
6434             XmNmarginWidth, BUTTON_WIDTH_MARGIN,
6435             XmNtopAttachment, XmATTACH_WIDGET,
6436             XmNtopWidget, tmpW,
6437             XmNtopOffset, MARGIN_SPACING,
6438             XmNleftAttachment, XmATTACH_POSITION,
6439             XmNleftPosition, 10,
6440             XmNrightAttachment, XmATTACH_POSITION,
6441             XmNrightPosition, 30,
6442             NULL);
6443     XtAddCallback(okBtn, XmNactivateCallback, colorOkCB, cd);
6444     XmStringFree(s1);
6445 
6446     applyBtn = XtVaCreateManagedWidget(
6447             "apply", xmPushButtonWidgetClass, form,
6448           XmNlabelString, s1=XmStringCreateSimple("Apply"),
6449           XmNtopAttachment, XmATTACH_WIDGET,
6450           XmNtopWidget, tmpW,
6451           XmNtopOffset, MARGIN_SPACING,
6452           XmNmnemonic, 'A',
6453           XmNleftAttachment, XmATTACH_POSITION,
6454           XmNleftPosition, 40,
6455           XmNrightAttachment, XmATTACH_POSITION,
6456           XmNrightPosition, 60, NULL);
6457     XtAddCallback(applyBtn, XmNactivateCallback, colorApplyCB, cd);
6458     XmStringFree(s1);
6459 
6460     closeBtn = XtVaCreateManagedWidget("close",
6461             xmPushButtonWidgetClass, form,
6462             XmNlabelString, s1=XmStringCreateSimple("Close"),
6463             XmNtopAttachment, XmATTACH_WIDGET,
6464             XmNtopWidget, tmpW,
6465             XmNtopOffset, MARGIN_SPACING,
6466             XmNleftAttachment, XmATTACH_POSITION,
6467             XmNleftPosition, 70,
6468             XmNrightAttachment, XmATTACH_POSITION,
6469             XmNrightPosition, 90,
6470             NULL);
6471     XtAddCallback(closeBtn, XmNactivateCallback, colorCloseCB, cd);
6472     XmStringFree(s1);
6473 
6474     /* Set initial default button */
6475     XtVaSetValues(form, XmNdefaultButton, okBtn, NULL);
6476     XtVaSetValues(form, XmNcancelButton, closeBtn, NULL);
6477 
6478     /* Set initial values */
6479     XmTextSetString(cd->textFgW,   GetPrefColorName(TEXT_FG_COLOR  ));
6480     XmTextSetString(cd->textBgW,   GetPrefColorName(TEXT_BG_COLOR  ));
6481     XmTextSetString(cd->selectFgW, GetPrefColorName(SELECT_FG_COLOR));
6482     XmTextSetString(cd->selectBgW, GetPrefColorName(SELECT_BG_COLOR));
6483     XmTextSetString(cd->hiliteFgW, GetPrefColorName(HILITE_FG_COLOR));
6484     XmTextSetString(cd->hiliteBgW, GetPrefColorName(HILITE_BG_COLOR));
6485     XmTextSetString(cd->lineNoFgW, GetPrefColorName(LINENO_FG_COLOR));
6486     XmTextSetString(cd->cursorFgW, GetPrefColorName(CURSOR_FG_COLOR));
6487 
6488     /* Handle mnemonic selection of buttons and focus to dialog */
6489     AddDialogMnemonicHandler(form, FALSE);
6490 
6491     /* put up dialog */
6492     ManageDialogCenteredOnPointer(form);
6493 }
6494 
6495 /*
6496 **  This function passes up a pointer to the static name of the default
6497 **  shell, currently defined as the user's login shell.
6498 **  In case of errors, the fallback of "sh" will be returned.
6499 */
getDefaultShell(void)6500 static const char* getDefaultShell(void)
6501 {
6502     struct passwd* passwdEntry = NULL;
6503     static char shellBuffer[MAXPATHLEN + 1] = "sh";
6504 
6505     passwdEntry = getpwuid(getuid());   /*  getuid() never fails.  */
6506 
6507     if (NULL == passwdEntry)
6508     {
6509         /*  Something bad happened! Do something, quick!  */
6510         perror("nedit: Failed to get passwd entry (falling back to 'sh')");
6511         return "sh";
6512     }
6513 
6514     /*  *passwdEntry may be overwritten  */
6515     /*  TODO: To make this and other function calling getpwuid() more robust,
6516         passwdEntry should be kept in a central position (Core->sysinfo?).
6517         That way, local code would always get a current copy of passwdEntry,
6518         but could still be kept lean.  The obvious alternative of a central
6519         facility within NEdit to access passwdEntry would increase coupling
6520         and would have to cover a lot of assumptions.  */
6521     strncpy(shellBuffer, passwdEntry->pw_shell, MAXPATHLEN);
6522     shellBuffer[MAXPATHLEN] = '\0';
6523 
6524     return shellBuffer;
6525 }
6526