libutil: add O_NOCTTY back to old pty open code
[minix.git] / commands / elvis / opts.c
blob7552ac6fbb9b823f936e57f25259d79e7471dd10
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 #include "ctype.h"
18 #include <sys/null.h>
19 extern char *getenv();
21 /* maximum width to permit for strings, including ="" */
22 #define MAXWIDTH 20
24 /* These are the default values of all options */
25 char o_autoindent[1] = {FALSE};
26 char o_autoprint[1] = {TRUE};
27 char o_autotab[1] = {TRUE};
28 char o_autowrite[1] = {FALSE};
29 char o_columns[3] = {80, 32, 255};
30 char o_directory[30] = TMPDIR;
31 char o_edcompatible[1] = {FALSE};
32 char o_equalprg[80] = {"fmt"};
33 char o_errorbells[1] = {TRUE};
34 char o_exrefresh[1] = {TRUE};
35 char o_ignorecase[1] = {FALSE};
36 char o_keytime[3] = {1, 0, 50};
37 char o_keywordprg[80] = {KEYWORDPRG};
38 char o_lines[3] = {25, 2, 96};
39 char o_list[1] = {FALSE};
40 char o_number[1] = {FALSE};
41 char o_readonly[1] = {FALSE};
42 char o_remap[1] = {TRUE};
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_flash[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] = {0, 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_MODELINES
104 char o_modelines[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 WSET 0x20 /* is this the "window" size option? */
134 #define MR 0x40 /* does this option affect the way text is displayed? */
135 struct
137 char *name; /* name of an option */
138 char *nm; /* short name of an option */
139 char type; /* type of an option */
140 char flags; /* boolean: has this option been set? */
141 char *value; /* value */
143 opts[] =
145 /* name type flags value */
146 { "autoindent", "ai", BOOL, CANSET, o_autoindent },
147 { "autoprint", "ap", BOOL, CANSET, o_autoprint },
148 { "autotab", "at", BOOL, CANSET, o_autotab },
149 { "autowrite", "aw", BOOL, CANSET, o_autowrite },
150 #ifndef CRUNCH
151 { "beautify", "bf", BOOL, CANSET, o_beautify },
152 #endif
153 #ifndef NO_ERRLIST
154 { "cc", "cc", STR, CANSET, o_cc },
155 #endif
156 #ifndef NO_CHARATTR
157 { "charattr", "ca", BOOL, CANSET|MR, o_charattr },
158 #endif
159 { "columns", "co", NUM, SET|NOSAVE|MR, o_columns },
160 #ifndef NO_DIGRAPH
161 { "digraph", "dig", BOOL, CANSET, o_digraph },
162 #endif
163 { "directory", "dir", STR, RCSET, o_directory },
164 { "edcompatible","ed", BOOL, CANSET, o_edcompatible },
165 { "equalprg", "ep", STR, CANSET, o_equalprg },
166 { "errorbells", "eb", BOOL, CANSET, o_errorbells },
167 #ifndef CRUNCH
168 { "exrc", "exrc", BOOL, CANSET, o_exrc },
169 #endif
170 { "exrefresh", "er", BOOL, CANSET, o_exrefresh },
171 { "flash", "vbell",BOOL, CANSET, o_flash },
172 #ifndef NO_DIGRAPH
173 { "flipcase", "fc", STR, CANSET, o_flipcase },
174 #endif
175 #ifndef NO_SENTENCE
176 { "hideformat", "hf", BOOL, CANSET|MR, o_hideformat },
177 #endif
178 { "ignorecase", "ic", BOOL, CANSET, o_ignorecase },
179 #ifndef NO_EXTENSIONS
180 { "inputmode", "im", BOOL, CANSET, o_inputmode },
181 #endif
182 { "keytime", "kt", NUM, CANSET, o_keytime },
183 { "keywordprg", "kp", STR, CANSET, o_keywordprg },
184 { "lines", "ls", NUM, SET|NOSAVE|MR, o_lines },
185 { "list", "li", BOOL, CANSET|MR, o_list },
186 #ifndef NO_MAGIC
187 { "magic", "ma", BOOL, CANSET, o_magic },
188 #endif
189 #ifndef NO_ERRLIST
190 { "make", "mk", STR, CANSET, o_make },
191 #endif
192 #ifndef CRUNCH
193 { "mesg", "me", BOOL, CANSET, o_mesg },
194 #endif
195 #ifndef NO_MODELINES
196 { "modelines", "ml", BOOL, CANSET, o_modelines },
197 #endif
198 #ifndef CRUNCH
199 { "more", "mo", BOOL, CANSET, o_more },
200 { "novice", "nov", BOOL, CANSET, o_novice },
201 #endif
202 { "number", "nu", BOOL, CANSET|MR, o_number },
203 #ifndef NO_SENTENCE
204 { "paragraphs", "para", STR, CANSET, o_paragraphs },
205 #endif
206 #if MSDOS
207 { "pcbios", "pc", BOOL, SET|NOSAVE, o_pcbios },
208 #endif
209 #ifndef CRUNCH
210 { "prompt", "pr", BOOL, CANSET, o_prompt },
211 #endif
212 { "readonly", "ro", BOOL, CANSET, o_readonly },
213 { "remap", "remap",BOOL, CANSET, o_remap },
214 { "report", "re", NUM, CANSET, o_report },
215 #ifndef NO_EXTENSIONS
216 { "ruler", "ru", BOOL, CANSET, o_ruler },
217 #endif
218 { "scroll", "sc", NUM, CANSET, o_scroll },
219 #ifndef NO_SENTENCE
220 { "sections", "sect", STR, CANSET, o_sections },
221 #endif
222 { "shell", "sh", STR, CANSET, o_shell },
223 #ifndef NO_SHOWMATCH
224 { "showmatch", "sm", BOOL, CANSET, o_showmatch },
225 #endif
226 #ifndef NO_SHOWMODE
227 { "showmode", "smd", BOOL, CANSET, o_smd },
228 #endif
229 { "shiftwidth", "sw", NUM, CANSET, o_shiftwidth },
230 { "sidescroll", "ss", NUM, CANSET, o_sidescroll },
231 { "sync", "sy", BOOL, CANSET, o_sync },
232 { "tabstop", "ts", NUM, CANSET|MR, o_tabstop },
233 #ifndef CRUNCH
234 { "taglength", "tl", NUM, CANSET, o_taglength },
235 #endif
236 { "term", "te", STR, SET, o_term },
237 #ifndef CRUNCH
238 { "terse", "tr", BOOL, CANSET, o_terse },
239 { "timeout", "to", BOOL, CANSET, o_keytime },
240 #endif
241 #ifndef CRUNCH
242 { "window", "wi", NUM, CANSET|MR|WSET, o_window },
243 { "wrapmargin", "wm", NUM, CANSET, o_wrapmargin },
244 #endif
245 { "wrapscan", "ws", BOOL, CANSET, o_wrapscan },
246 #ifndef CRUNCH
247 { "writeany", "wr", BOOL, CANSET, o_writeany },
248 #endif
249 { NULL, NULL, 0, CANSET, NULL }
253 /* This function initializes certain options from environment variables, etc. */
254 void initopts()
256 char *val;
257 int i;
259 /* set some stuff from environment variables */
260 #if MSDOS
261 if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */
262 #else
263 if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */
264 #endif
266 strcpy(o_shell, val);
269 strcpy(o_term, termtype);
270 #if MSDOS
271 if (strcmp(termtype, "pcbios"))
273 o_pcbios[0] = FALSE;
275 else
277 o_pcbios[0] = TRUE;
279 #endif
281 #if AMIGA || MSDOS || TOS
282 if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */
283 || (val = getenv("TEMP")))
284 strcpy(o_directory, val);
285 #endif
287 #ifndef CRUNCH
288 if ((val = getenv("LINES")) && atoi(val) > 4) /* yes, ASSIGNMENT! */
290 LINES = atoi(val);
292 if ((val = getenv("COLUMNS")) && atoi(val) > 30) /* yes, ASSIGNMENT! */
294 COLS = atoi(val);
296 #endif
297 *o_lines = LINES;
298 *o_columns = COLS;
299 *o_scroll = LINES / 2 - 1;
300 #ifndef CRUNCH
301 if (o_window[0] == 0)
303 o_window[0] = o_window[2] = *o_lines;
305 #endif
307 /* disable the flash option if we don't know how to do a flash */
308 if (!has_VB)
310 for (i = 0; opts[i].value != o_flash; i++)
313 opts[i].flags &= ~CANSET;
314 *o_flash = FALSE;
317 #ifndef NO_DIGRAPH
318 # ifdef CS_LATIN1
319 for (i = 0, val = o_flipcase; i < 32; i++)
321 /* leave out the multiply/divide symbols */
322 if (i == 23)
323 continue;
325 /* add lower/uppercase pair */
326 *val++ = i + 0xe0;
327 *val++ = i + 0xc0;
329 *val = '\0';
330 # endif /* CS_LATIN1 */
332 /* initialize the ctype package */
333 _ct_init(o_flipcase);
334 #else
335 _ct_init("");
336 #endif /* not NO_DIGRAPH */
339 /* This function lists the current values of all options */
340 void dumpopts(all)
341 int all; /* boolean: dump all options, or just set ones? */
343 #ifndef NO_OPTCOLS
344 int i, j, k;
345 char nbuf[4]; /* used for converting numbers to ASCII */
346 int widths[5]; /* width of each column, including gap */
347 int ncols; /* number of columns */
348 int nrows; /* number of options per column */
349 int nset; /* number of options to be output */
350 int width; /* width of a particular option */
351 int todump[60]; /* indicies of options to be dumped */
353 /* step 1: count the number of set options */
354 for (nset = i = 0; opts[i].name; i++)
356 if (all || (opts[i].flags & SET))
358 todump[nset++] = i;
362 /* step two: try to use as many columns as possible */
363 for (ncols = (nset > 5 ? 5 : nset); ncols > 1; ncols--)
365 /* how many would go in this column? */
366 nrows = (nset + ncols - 1) / ncols;
368 /* figure out the width of each column */
369 for (i = 0; i < ncols; i++)
371 widths[i] = 0;
372 for (j = 0, k = nrows * i; j < nrows && k < nset; j++, k++)
374 /* figure out the width of a particular option */
375 switch (opts[todump[k]].type)
377 case BOOL:
378 if (!*opts[todump[k]].value)
379 width = 2;
380 else
381 width = 0;
382 break;
384 case STR:
385 width = 3 + strlen(opts[todump[k]].value);
386 if (width > MAXWIDTH)
387 width = MAXWIDTH;
388 break;
390 case NUM:
391 width = 4;
392 break;
394 width += strlen(opts[todump[k]].name);
396 /* if this is the widest so far, widen col */
397 if (width > widths[i])
399 widths[i] = width;
405 /* if the total width is narrow enough, then use it */
406 for (width = -2, i = 0; i < ncols; i++)
408 width += widths[i] + 2;
410 if (width < COLS - 1)
412 break;
416 /* step 3: output the columns */
417 nrows = (nset + ncols - 1) / ncols;
418 for (i = 0; i < nrows; i++)
420 for (j = 0; j < ncols; j++)
422 /* if we hit the end of the options, quit */
423 k = i + j * nrows;
424 if (k >= nset)
426 break;
429 /* output this option's value */
430 width = 0;
431 switch (opts[todump[k]].type)
433 case BOOL:
434 if (!*opts[todump[k]].value)
436 qaddch('n');
437 qaddch('o');
438 width = 2;
440 qaddstr(opts[todump[k]].name);
441 width += strlen(opts[todump[k]].name);
442 break;
444 case NUM:
445 sprintf(nbuf, "%-3d", UCHAR(*opts[todump[k]].value));
446 qaddstr(opts[todump[k]].name);
447 qaddch('=');
448 qaddstr(nbuf);
449 width = 4 + strlen(opts[todump[k]].name);
450 break;
452 case STR:
453 qaddstr(opts[todump[k]].name);
454 qaddch('=');
455 qaddch('"');
456 strcpy(tmpblk.c, opts[todump[k]].value);
457 width = 3 + strlen(tmpblk.c);
458 if (width > MAXWIDTH)
460 width = MAXWIDTH;
461 strcpy(tmpblk.c + MAXWIDTH - 6, "...");
463 qaddstr(tmpblk.c);
464 qaddch('"');
465 width += strlen(opts[todump[k]].name);
466 break;
469 /* pad the field to the correct size */
470 if (k + nrows <= nset)
472 while (width < widths[j] + 2)
474 qaddch(' ');
475 width++;
479 addch('\n');
480 exrefresh();
482 #else
483 int i;
484 int col;
485 char nbuf[4];
487 for (i = col = 0; opts[i].name; i++)
489 /* if not set and not all, ignore this option */
490 if (!all && !(opts[i].flags & SET))
492 continue;
495 /* align this option in one of the columns */
496 if (col > 52)
498 addch('\n');
499 col = 0;
501 else if (col > 26)
503 while (col < 52)
505 qaddch(' ');
506 col++;
509 else if (col > 0)
511 while (col < 26)
513 qaddch(' ');
514 col++;
518 switch (opts[i].type)
520 case BOOL:
521 if (!*opts[i].value)
523 qaddch('n');
524 qaddch('o');
525 col += 2;
527 qaddstr(opts[i].name);
528 col += strlen(opts[i].name);
529 break;
531 case NUM:
532 sprintf(nbuf, "%-3d", UCHAR(*opts[i].value));
533 qaddstr(opts[i].name);
534 qaddch('=');
535 qaddstr(nbuf);
536 col += 4 + strlen(opts[i].name);
537 break;
539 case STR:
540 qaddstr(opts[i].name);
541 qaddch('=');
542 qaddch('"');
543 qaddstr(opts[i].value);
544 qaddch('"');
545 col += 3 + strlen(opts[i].name) + strlen(opts[i].value);
546 break;
548 exrefresh();
550 if (col > 0)
552 addch('\n');
553 exrefresh();
555 #endif
558 #ifndef NO_MKEXRC
559 /* This function saves the current configuration of options to a file */
560 void saveopts(fd)
561 int fd; /* file descriptor to write to */
563 int i;
564 char buf[256], *pos;
566 /* write each set options */
567 for (i = 0; opts[i].name; i++)
569 /* if unset or unsettable, ignore this option */
570 if ((opts[i].flags & (SET|CANSET|NOSAVE)) != (SET|CANSET))
572 continue;
575 strcpy(buf, "set ");
576 pos = &buf[4];
577 switch (opts[i].type)
579 case BOOL:
580 if (!*opts[i].value)
582 *pos++='n';
583 *pos++='o';
585 strcpy(pos, opts[i].name);
586 strcat(pos, "\n");
587 break;
589 case NUM:
590 sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff);
591 break;
593 case STR:
594 sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value);
595 break;
597 twrite(fd, buf, (unsigned)strlen(buf));
600 #endif
603 /* This function changes the values of one or more options. */
604 void setopts(assignments)
605 char *assignments; /* a string containing option assignments */
607 char *name; /* name of variable in assignments */
608 char *value; /* value of the variable */
609 char *scan; /* used for moving through strings */
610 char *build; /* used for copying chars from "scan" */
611 char *prefix; /* pointer to "neg" or "no" at front of a boolean */
612 int quote; /* boolean: inside '"' quotes? */
613 int i, j;
615 #ifndef CRUNCH
616 /* reset the upper limit of "window" option to lines-1 */
617 *o_window = *o_lines - 1;
618 #endif
620 /* for each assignment... */
621 for (name = assignments; *name; )
623 /* skip whitespace */
624 if (*name == ' ' || *name == '\t')
626 name++;
627 continue;
630 /* after the name, find the value (if any) */
631 for (scan = name; isalnum(*scan); scan++)
634 if (*scan == '=')
636 *scan++ = '\0';
637 value = build = scan;
638 for (quote = FALSE; *scan && (quote || !isspace(*scan)); scan++)
640 if (*scan == '"')
642 quote = !quote;
644 else if (*scan == '\\' && scan[1])
646 *build++ = *++scan;
648 else
650 *build++ = *scan;
653 if (*scan)
654 scan++;
655 *build = '\0';
657 else /* no "=" so it is probably boolean... */
659 if (*scan)
661 *scan++ = '\0';
663 value = NULL;
664 prefix = name;
665 #ifndef CRUNCH
666 if (!strcmp(name, "novice"))
667 /* don't check for a "no" prefix */;
668 else
669 #endif
670 if (prefix[0] == 'n' && prefix[1] == 'o')
671 name += 2;
672 else if (prefix[0] == 'n' && prefix[1] == 'e' && prefix[2] == 'g')
673 name += 3;
676 /* find the variable */
677 for (i = 0;
678 opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name);
679 i++)
683 /* change the variable */
684 if (!opts[i].name)
686 msg("invalid option name \"%s\"", name);
688 else if ((opts[i].flags & CANSET) != CANSET)
690 msg("option \"%s\" can't be altered", name);
692 else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L)
694 msg("option \"%s\" can only be set in a %s file", name, EXRC);
696 else if (value)
698 switch (opts[i].type)
700 case BOOL:
701 msg("option \"[no]%s\" is boolean", name);
702 break;
704 case NUM:
705 j = atoi(value);
706 if (j == 0 && *value != '0')
708 msg("option \"%s\" must have a numeric value", name);
710 else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff))
712 msg("option \"%s\" must have a value between %d and %d",
713 name, opts[i].value[1], opts[i].value[2] & 0xff);
715 else
717 *opts[i].value = atoi(value);
718 opts[i].flags |= SET;
720 break;
722 case STR:
723 strcpy(opts[i].value, value);
724 opts[i].flags |= SET;
725 break;
727 if (opts[i].flags & MR)
729 redraw(MARK_UNSET, FALSE);
731 #ifndef CRUNCH
732 if (opts[i].flags & WSET)
734 wset = TRUE;
736 #endif
738 else /* valid option, no value */
740 if (opts[i].type == BOOL)
742 if (prefix == name)
743 *opts[i].value = TRUE;
744 else if (prefix[1] == 'o')
745 *opts[i].value = FALSE;
746 else
747 *opts[i].value = !*opts[i].value;
749 opts[i].flags |= SET;
750 if (opts[i].flags & MR)
752 redraw(MARK_UNSET, FALSE);
755 else
757 msg("option \"%s\" must be given a value", name);
761 /* move on to the next option */
762 name = scan;
765 /* special processing ... */
767 #ifndef CRUNCH
768 /* if "novice" is set, then ":set report=1 showmode nomagic" */
769 if (*o_novice)
771 *o_report = 1;
772 # ifndef NO_SHOWMODE
773 *o_smd = TRUE;
774 # endif
775 # ifndef NO_MAGIC
776 *o_magic = FALSE;
777 # endif
779 #endif
781 /* if "readonly" then set the READONLY flag for this file */
782 if (*o_readonly)
784 setflag(file, READONLY);
787 #ifndef NO_DIGRAPH
788 /* re-initialize the ctype package */
789 _ct_init(o_flipcase);
790 #endif /* not NO_DIGRAPH */
792 /* copy o_lines and o_columns into LINES and COLS */
793 LINES = (*o_lines & 255);
794 COLS = (*o_columns & 255);