Initial revision
[nvi.git] / common / options.c
blob92798c93703252e8192bfcd5f5cf12bd06de6e5f
1 /* opts.c */
3 /* Author:
4 * Steve Kirkendall
5 * 14407 SW Teal Blvd. #C
6 * Beaverton, OR 97005
7 * kirkenda@cs.pdx.edu
8 */
11 /* This file contains the code that manages the run-time options -- The
12 * values that can be modified via the "set" command.
15 #include "config.h"
16 #include "vi.h"
17 #ifndef NULL
18 #define NULL (char *)0
19 #endif
20 extern char *getenv();
22 /* maximum width to permit for strings, including ="" */
23 #define MAXWIDTH 20
25 /* These are the default values of all options */
26 char o_autoindent[1] = {FALSE};
27 char o_autoprint[1] = {TRUE};
28 char o_autotab[1] = {TRUE};
29 char o_autowrite[1] = {FALSE};
30 char o_columns[3] = {80, 32, 255};
31 char o_directory[30] = TMPDIR;
32 char o_edcompatible[1] = {FALSE};
33 char o_equalprg[80] = {"fmt"};
34 char o_errorbells[1] = {TRUE};
35 char o_exrefresh[1] = {TRUE};
36 char o_ignorecase[1] = {FALSE};
37 char o_keytime[3] = {2, 0, 50};
38 char o_keywordprg[80] = {KEYWORDPRG};
39 char o_lines[3] = {25, 2, 66};
40 char o_list[1] = {FALSE};
41 char o_number[1] = {FALSE};
42 char o_readonly[1] = {FALSE};
43 char o_report[3] = {5, 1, 127};
44 char o_scroll[3] = {12, 1, 127};
45 char o_shell[60] = SHELL;
46 char o_shiftwidth[3] = {8, 1, 255};
47 char o_sidescroll[3] = {8, 1, 40};
48 char o_sync[1] = {NEEDSYNC};
49 char o_tabstop[3] = {8, 1, 40};
50 char o_term[30] = "?";
51 char o_vbell[1] = {TRUE};
52 char o_warn[1] = {TRUE};
53 char o_wrapscan[1] = {TRUE};
55 #ifndef CRUNCH
56 char o_beautify[1] = {FALSE};
57 char o_exrc[1] = {FALSE};
58 char o_mesg[1] = {TRUE};
59 char o_more[1] = {TRUE};
60 char o_novice[1] = {FALSE};
61 char o_prompt[1] = {TRUE};
62 char o_taglength[3] = {0, 0, 30};
63 char o_terse[1] = {FALSE};
64 char o_window[3] = {24, 1, 24};
65 char o_wrapmargin[3] = {0, 0, 255};
66 char o_writeany[1] = {FALSE};
67 #endif
69 #ifndef NO_ERRLIST
70 char o_cc[30] = {CC_COMMAND};
71 char o_make[30] = {MAKE_COMMAND};
72 #endif
74 #ifndef NO_CHARATTR
75 char o_charattr[1] = {FALSE};
76 #endif
78 #ifndef NO_DIGRAPH
79 char o_digraph[1] = {FALSE};
80 char o_flipcase[80]
81 # ifdef CS_IBMPC
82 = {"\207\200\201\232\202\220\204\216\206\217\221\222\224\231\244\245"}
83 # endif
84 # ifdef CS_LATIN1
85 /* initialized by initopts() */
86 # endif
88 #endif
90 #ifndef NO_SENTENCE
91 char o_hideformat[1] = {FALSE};
92 #endif
94 #ifndef NO_EXTENSIONS
95 char o_inputmode[1] = {FALSE};
96 char o_ruler[1] = {FALSE};
97 #endif
99 #ifndef NO_MAGIC
100 char o_magic[1] = {TRUE};
101 #endif
103 #ifndef NO_MODELINE
104 char o_modeline[1] = {FALSE};
105 #endif
107 #ifndef NO_SENTENCE
108 char o_paragraphs[30] = "PPppIPLPQP";
109 char o_sections[30] = "NHSHSSSEse";
110 #endif
112 #if MSDOS
113 char o_pcbios[1] = {TRUE};
114 #endif
116 #ifndef NO_SHOWMATCH
117 char o_showmatch[1] = {FALSE};
118 #endif
120 #ifndef NO_SHOWMODE
121 char o_smd[1] = {FALSE};
122 #endif
125 /* The following describes the names & types of all options */
126 #define BOOL 0
127 #define NUM 1
128 #define STR 2
129 #define SET 0x01 /* this option has had its value altered */
130 #define CANSET 0x02 /* this option can be set at any time */
131 #define RCSET 0x06 /* this option can be set in a .exrc file only */
132 #define NOSAVE 0x0a /* this option should never be saved by mkexrc */
133 #define MR 0x40 /* does this option affect the way text is displayed? */
134 struct
136 char *name; /* name of an option */
137 char *nm; /* short name of an option */
138 char type; /* type of an option */
139 char flags; /* boolean: has this option been set? */
140 char *value; /* value */
142 opts[] =
144 /* name type flags value */
145 { "autoindent", "ai", BOOL, CANSET, o_autoindent },
146 { "autoprint", "ap", BOOL, CANSET, o_autoprint },
147 { "autotab", "at", BOOL, CANSET, o_autotab },
148 { "autowrite", "aw", BOOL, CANSET, o_autowrite },
149 #ifndef CRUNCH
150 { "beautify", "bf", BOOL, CANSET, o_beautify },
151 #endif
152 #ifndef NO_ERRLIST
153 { "cc", "cc", STR, CANSET, o_cc },
154 #endif
155 #ifndef NO_CHARATTR
156 { "charattr", "ca", BOOL, CANSET|MR, o_charattr },
157 #endif
158 { "columns", "co", NUM, SET|NOSAVE|MR, o_columns },
159 #ifndef NO_DIGRAPH
160 { "digraph", "dig", BOOL, CANSET, o_digraph },
161 #endif
162 { "directory", "dir", STR, RCSET, o_directory },
163 { "edcompatible","ed", BOOL, CANSET, o_edcompatible },
164 { "equalprg", "ep", STR, CANSET, o_equalprg },
165 { "errorbells", "eb", BOOL, CANSET, o_errorbells },
166 #ifndef CRUNCH
167 { "exrc", "exrc", BOOL, CANSET, o_exrc },
168 #endif
169 { "exrefresh", "er", BOOL, CANSET, o_exrefresh },
170 #ifdef SYSV_COMPAT
171 { "flash", "fl", BOOL, CANSET, o_vbell },
172 #endif
173 #ifndef NO_DIGRAPH
174 { "flipcase", "fc", STR, CANSET, o_flipcase },
175 #endif
176 #ifndef NO_SENTENCE
177 { "hideformat", "hf", BOOL, CANSET|MR, o_hideformat },
178 #endif
179 { "ignorecase", "ic", BOOL, CANSET, o_ignorecase },
180 #ifndef NO_EXTENSIONS
181 { "inputmode", "im", BOOL, CANSET, o_inputmode },
182 #endif
183 { "keytime", "kt", NUM, CANSET, o_keytime },
184 { "keywordprg", "kp", STR, CANSET, o_keywordprg },
185 { "lines", "ls", NUM, SET|NOSAVE|MR, o_lines },
186 { "list", "li", BOOL, CANSET|MR, o_list },
187 #ifndef NO_MAGIC
188 { "magic", "ma", BOOL, CANSET, o_magic },
189 #endif
190 #ifndef NO_ERRLIST
191 { "make", "mk", STR, CANSET, o_make },
192 #endif
193 #ifndef CRUNCH
194 { "mesg", "me", BOOL, CANSET, o_mesg },
195 #endif
196 #ifndef NO_MODELINE
197 # ifdef SYSV_COMPAT
198 { "modelines", "ml", BOOL, CANSET, o_modeline },
199 # else
200 { "modeline", "ml", BOOL, CANSET, o_modeline },
201 # endif
202 #endif
203 #ifndef CRUNCH
204 { "more", "mo", BOOL, CANSET, o_more },
205 { "novice", "nov", BOOL, CANSET, o_novice },
206 #endif
207 { "number", "nu", BOOL, CANSET|MR, o_number },
208 #ifndef NO_SENTENCE
209 { "paragraphs", "pa", STR, CANSET, o_paragraphs },
210 #endif
211 #if MSDOS
212 { "pcbios", "pc", BOOL, SET|NOSAVE, o_pcbios },
213 #endif
214 #ifndef CRUNCH
215 { "prompt", "pr", BOOL, CANSET, o_prompt },
216 #endif
217 { "readonly", "ro", BOOL, CANSET, o_readonly },
218 { "report", "re", NUM, CANSET, o_report },
219 #ifndef NO_EXTENSIONS
220 { "ruler", "ru", BOOL, CANSET, o_ruler },
221 #endif
222 { "scroll", "sc", NUM, CANSET, o_scroll },
223 #ifndef NO_SENTENCE
224 { "sections", "se", STR, CANSET, o_sections },
225 #endif
226 { "shell", "sh", STR, CANSET, o_shell },
227 #ifndef NO_SHOWMATCH
228 { "showmatch", "sm", BOOL, CANSET, o_showmatch },
229 #endif
230 #ifndef NO_SHOWMODE
231 { "showmode", "smd", BOOL, CANSET, o_smd },
232 #endif
233 { "shiftwidth", "sw", NUM, CANSET, o_shiftwidth },
234 { "sidescroll", "ss", NUM, CANSET, o_sidescroll },
235 { "sync", "sy", BOOL, CANSET, o_sync },
236 { "tabstop", "ts", NUM, CANSET|MR, o_tabstop },
237 #ifndef CRUNCH
238 { "taglength", "tl", NUM, CANSET, o_taglength },
239 #endif
240 { "term", "te", STR, SET, o_term },
241 #ifndef CRUNCH
242 { "terse", "tr", BOOL, CANSET, o_terse },
243 { "timeout", "to", BOOL, CANSET, o_keytime },
244 #endif
245 #ifndef SYSV_COMPAT
246 { "vbell", "vb", BOOL, CANSET, o_vbell },
247 #endif
248 { "warn", "wa", BOOL, CANSET, o_warn },
249 #ifndef CRUNCH
250 { "window", "wi", NUM, CANSET|MR, o_window },
251 { "wrapmargin", "wm", NUM, CANSET, o_wrapmargin },
252 #endif
253 { "wrapscan", "ws", BOOL, CANSET, o_wrapscan },
254 #ifndef CRUNCH
255 { "writeany", "wr", BOOL, CANSET, o_writeany },
256 #endif
257 { NULL, NULL, 0, CANSET, NULL }
261 /* This function initializes certain options from environment variables, etc. */
262 void initopts()
264 char *val;
265 int i;
267 /* set some stuff from environment variables */
268 #if MSDOS
269 if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */
270 #else
271 if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */
272 #endif
274 strcpy(o_shell, val);
277 strcpy(o_term, termtype);
278 #if MSDOS
279 if (strcmp(termtype, "pcbios"))
281 o_pcbios[0] = FALSE;
283 else
285 o_pcbios[0] = TRUE;
287 #endif
289 #if MSDOS || TOS
290 if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */
291 || (val = getenv("TEMP")))
292 strcpy(o_directory, val);
293 #endif
295 #ifndef CRUNCH
296 if ((val = getenv("LINES")) && atoi(val) > 30) /* yes, ASSIGNMENT! */
298 LINES = atoi(val);
300 if ((val = getenv("COLUMNS")) && atoi(val) > 4) /* yes, ASSIGNMENT! */
302 COLS = atoi(val);
304 #endif
305 *o_lines = LINES;
306 *o_columns = COLS;
307 *o_scroll = LINES / 2 - 1;
308 #ifndef CRUNCH
309 *o_window = *o_lines - 1;
310 #endif
312 /* disable the vbell option if we don't know how to do a vbell */
313 if (!has_VB)
315 for (i = 0; opts[i].value != o_vbell; i++)
318 opts[i].flags &= ~CANSET;
319 *o_vbell = FALSE;
322 #ifndef NO_DIGRAPH
323 # ifdef CS_LATIN1
324 for (i = 0, val = o_flipcase; i < 32; i++)
326 /* leave out the multiply/divide symbols */
327 if (i == 23)
328 continue;
330 /* add lower/uppercase pair */
331 *val++ = i + 0xe0;
332 *val++ = i + 0xc0;
334 *val = '\0';
335 # endif /* CS_LATIN1 */
337 /* initialize the ctype package */
338 _ct_init(o_flipcase);
339 #else
340 _ct_init("");
341 #endif /* not NO_DIGRAPH */
344 /* This function lists the current values of all options */
345 void dumpopts(all)
346 int all; /* boolean: dump all options, or just set ones? */
348 #ifndef NO_OPTCOLS
349 int i, j, k;
350 char nbuf[4]; /* used for converting numbers to ASCII */
351 int widths[5]; /* width of each column, including gap */
352 int ncols; /* number of columns */
353 int nrows; /* number of options per column */
354 int nset; /* number of options to be output */
355 int width; /* width of a particular option */
356 int todump[60]; /* indicies of options to be dumped */
358 /* step 1: count the number of set options */
359 for (nset = i = 0; opts[i].name; i++)
361 if (all || (opts[i].flags & SET))
363 todump[nset++] = i;
367 /* step two: try to use as many columns as possible */
368 for (ncols = (nset > 5 ? 5 : nset); ncols > 1; ncols--)
370 /* how many would go in this column? */
371 nrows = (nset + ncols - 1) / ncols;
373 /* figure out the width of each column */
374 for (i = 0; i < ncols; i++)
376 widths[i] = 0;
377 for (j = 0, k = nrows * i; j < nrows && k < nset; j++, k++)
379 /* figure out the width of a particular option */
380 switch (opts[todump[k]].type)
382 case BOOL:
383 if (!*opts[todump[k]].value)
384 width = 2;
385 else
386 width = 0;
387 break;
389 case STR:
390 width = 3 + strlen(opts[todump[k]].value);
391 if (width > MAXWIDTH)
392 width = MAXWIDTH;
393 break;
395 case NUM:
396 width = 4;
397 break;
399 width += strlen(opts[todump[k]].name);
401 /* if this is the widest so far, widen col */
402 if (width > widths[i])
404 widths[i] = width;
410 /* if the total width is narrow enough, then use it */
411 for (width = -2, i = 0; i < ncols; i++)
413 width += widths[i] + 2;
415 if (width < COLS - 1)
417 break;
421 /* step 3: output the columns */
422 nrows = (nset + ncols - 1) / ncols;
423 for (i = 0; i < nrows; i++)
425 for (j = 0; j < ncols; j++)
427 /* if we hit the end of the options, quit */
428 k = i + j * nrows;
429 if (k >= nset)
431 break;
434 /* output this option's value */
435 width = 0;
436 switch (opts[todump[k]].type)
438 case BOOL:
439 if (!*opts[todump[k]].value)
441 qaddch('n');
442 qaddch('o');
443 width = 2;
445 qaddstr(opts[todump[k]].name);
446 width += strlen(opts[todump[k]].name);
447 break;
449 case NUM:
450 sprintf(nbuf, "%-3d", UCHAR(*opts[todump[k]].value));
451 qaddstr(opts[todump[k]].name);
452 qaddch('=');
453 qaddstr(nbuf);
454 width = 4 + strlen(opts[todump[k]].name);
455 break;
457 case STR:
458 qaddstr(opts[todump[k]].name);
459 qaddch('=');
460 qaddch('"');
461 strcpy(tmpblk.c, opts[todump[k]].value);
462 width = 3 + strlen(tmpblk.c);
463 if (width > MAXWIDTH)
465 width = MAXWIDTH;
466 strcpy(tmpblk.c + MAXWIDTH - 6, "...");
468 qaddstr(tmpblk.c);
469 qaddch('"');
470 width += strlen(opts[todump[k]].name);
471 break;
474 /* pad the field to the correct size */
475 if (k + nrows <= nset)
477 while (width < widths[j] + 2)
479 qaddch(' ');
480 width++;
484 addch('\n');
485 exrefresh();
487 #else
488 int i;
489 int col;
490 char nbuf[4];
492 for (i = col = 0; opts[i].name; i++)
494 /* if not set and not all, ignore this option */
495 if (!all && !(opts[i].flags & SET))
497 continue;
500 /* align this option in one of the columns */
501 if (col > 52)
503 addch('\n');
504 col = 0;
506 else if (col > 26)
508 while (col < 52)
510 qaddch(' ');
511 col++;
514 else if (col > 0)
516 while (col < 26)
518 qaddch(' ');
519 col++;
523 switch (opts[i].type)
525 case BOOL:
526 if (!*opts[i].value)
528 qaddch('n');
529 qaddch('o');
530 col += 2;
532 qaddstr(opts[i].name);
533 col += strlen(opts[i].name);
534 break;
536 case NUM:
537 sprintf(nbuf, "%-3d", UCHAR(*opts[i].value));
538 qaddstr(opts[i].name);
539 qaddch('=');
540 qaddstr(nbuf);
541 col += 4 + strlen(opts[i].name);
542 break;
544 case STR:
545 qaddstr(opts[i].name);
546 qaddch('=');
547 qaddch('"');
548 qaddstr(opts[i].value);
549 qaddch('"');
550 col += 3 + strlen(opts[i].name) + strlen(opts[i].value);
551 break;
553 exrefresh();
555 if (col > 0)
557 addch('\n');
558 exrefresh();
560 #endif
563 #ifndef NO_MKEXRC
564 /* This function saves the current configuration of options to a file */
565 void saveopts(fd)
566 int fd; /* file descriptor to write to */
568 int i;
569 char buf[256], *pos;
571 /* write each set options */
572 for (i = 0; opts[i].name; i++)
574 /* if unset or unsettable, ignore this option */
575 if ((opts[i].flags & (SET|CANSET|NOSAVE)) != (SET|CANSET))
577 continue;
580 strcpy(buf, "set ");
581 pos = &buf[4];
582 switch (opts[i].type)
584 case BOOL:
585 if (!*opts[i].value)
587 *pos++='n';
588 *pos++='o';
590 strcpy(pos, opts[i].name);
591 strcat(pos, "\n");
592 break;
594 case NUM:
595 sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff);
596 break;
598 case STR:
599 sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value);
600 break;
602 twrite(fd, buf, strlen(buf));
605 #endif
608 /* This function changes the values of one or more options. */
609 void setopts(assignments)
610 char *assignments; /* a string containing option assignments */
612 char *name; /* name of variable in assignments */
613 char *value; /* value of the variable */
614 char *scan; /* used for moving through strings */
615 char *prefix; /* pointer to "~" or "no" at front of a boolean */
616 int i, j;
618 #ifndef CRUNCH
619 /* reset the upper limit of "window" option to lines-1 */
620 *o_window = *o_lines - 1;
621 #endif
623 /* for each assignment... */
624 for (name = assignments; *name; )
626 /* skip whitespace */
627 if (*name == ' ' || *name == '\t')
629 name++;
630 continue;
633 /* find the value, if any */
634 for (scan = name; *scan >= 'a' && *scan <= 'z'; scan++)
637 if (*scan == '=')
639 *scan++ = '\0';
640 if (*scan == '"' && !QTST(scan))
642 value = ++scan;
643 while (*scan && *scan != '"')
645 scan++;
647 if (*scan)
649 *scan++ = '\0';
652 else
654 value = scan;
655 while (*scan && (*scan != ' ' && *scan != '\t' || QTST(scan)))
657 scan++;
659 if (*scan)
661 *scan++ = '\0';
665 else /* no "=" so it is probably boolean... */
667 if (*scan)
669 *scan++ = '\0';
671 value = NULL;
672 prefix = name;
673 #ifndef CRUNCH
674 if (!strcmp(name, "novice"))
675 /* don't check for a "no" prefix */;
676 else
677 #endif
678 if (prefix[0] == 'n' && prefix[1] == 'o')
679 name += 2;
680 else if (prefix[0] == 'n' && prefix[1] == 'e' && prefix[2] == 'g')
681 name += 3;
684 /* find the variable */
685 for (i = 0;
686 opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name);
687 i++)
691 /* change the variable */
692 if (!opts[i].name)
694 msg("invalid option name \"%s\"", name);
696 else if ((opts[i].flags & CANSET) != CANSET)
698 msg("option \"%s\" can't be altered", name);
700 else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L)
702 msg("option \"%s\" can only be set in a %s file", name, EXRC);
704 else if (value)
706 switch (opts[i].type)
708 case BOOL:
709 msg("option \"[no]%s\" is boolean", name);
710 break;
712 case NUM:
713 j = atoi(value);
714 if (j == 0 && *value != '0')
716 msg("option \"%s\" must have a numeric value", name);
718 else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff))
720 msg("option \"%s\" must have a value between %d and %d",
721 name, opts[i].value[1], opts[i].value[2] & 0xff);
723 else
725 *opts[i].value = atoi(value);
726 opts[i].flags |= SET;
728 break;
730 case STR:
731 strcpy(opts[i].value, value);
732 opts[i].flags |= SET;
733 break;
735 if (opts[i].flags & MR)
737 redraw(MARK_UNSET, FALSE);
740 else /* valid option, no value */
742 if (opts[i].type == BOOL)
744 if (prefix == name)
745 *opts[i].value = TRUE;
746 else if (prefix[1] == 'o')
747 *opts[i].value = FALSE;
748 else
749 *opts[i].value = !*opts[i].value;
751 opts[i].flags |= SET;
752 if (opts[i].flags & MR)
754 redraw(MARK_UNSET, FALSE);
757 else
759 msg("option \"%s\" must be given a value", name);
763 /* move on to the next option */
764 name = scan;
767 /* special processing ... */
769 #ifndef CRUNCH
770 /* if "novice" is set, then ":set report=1 showmode nomagic" */
771 if (*o_novice)
773 *o_report = 1;
774 # ifndef NO_SHOWMODE
775 *o_smd = TRUE;
776 # endif
777 # ifndef NO_MAGIC
778 *o_magic = FALSE;
779 # endif
781 #endif
783 /* if "readonly" then set the READONLY flag for this file */
784 if (*o_readonly)
786 setflag(file, READONLY);
789 #ifndef NO_DIGRAPH
790 /* re-initialize the ctype package */
791 _ct_init(o_flipcase);
792 #endif /* not NO_DIGRAPH */
794 /* copy o_lines and o_columns into LINES and COLS */
795 LINES = (*o_lines & 255);
796 COLS = (*o_columns & 255);