1 1.7 mrg /* $NetBSD: options.c,v 1.7 2019/10/04 09:01:59 mrg Exp $ */ 2 1.1 christos /*- 3 1.1 christos * Copyright (c) 1991, 1993, 1994 4 1.1 christos * The Regents of the University of California. All rights reserved. 5 1.1 christos * Copyright (c) 1991, 1993, 1994, 1995, 1996 6 1.1 christos * Keith Bostic. All rights reserved. 7 1.1 christos * 8 1.1 christos * See the LICENSE file for redistribution information. 9 1.1 christos */ 10 1.1 christos 11 1.1 christos #include "config.h" 12 1.1 christos 13 1.3 christos #include <sys/cdefs.h> 14 1.3 christos #if 0 15 1.1 christos #ifndef lint 16 1.1 christos static const char sccsid[] = "Id: options.c,v 10.65 2002/01/18 22:34:43 skimo Exp (Berkeley) Date: 2002/01/18 22:34:43 "; 17 1.1 christos #endif /* not lint */ 18 1.3 christos #else 19 1.7 mrg __RCSID("$NetBSD: options.c,v 1.7 2019/10/04 09:01:59 mrg Exp $"); 20 1.3 christos #endif 21 1.1 christos 22 1.1 christos #include <sys/types.h> 23 1.1 christos #include <sys/queue.h> 24 1.1 christos #include <sys/stat.h> 25 1.1 christos #include <sys/time.h> 26 1.1 christos 27 1.1 christos #include <bitstring.h> 28 1.1 christos #include <ctype.h> 29 1.1 christos #include <errno.h> 30 1.1 christos #include <limits.h> 31 1.1 christos #include <stdio.h> 32 1.1 christos #include <stdlib.h> 33 1.1 christos #include <string.h> 34 1.1 christos #include <unistd.h> 35 1.1 christos 36 1.1 christos #include "common.h" 37 1.1 christos #include "../vi/vi.h" 38 1.1 christos #include "pathnames.h" 39 1.1 christos 40 1.1 christos static int opts_abbcmp __P((const void *, const void *)); 41 1.1 christos static int opts_cmp __P((const void *, const void *)); 42 1.1 christos static int opts_print __P((SCR *, OPTLIST const *)); 43 1.1 christos 44 1.1 christos #ifdef USE_WIDECHAR 45 1.1 christos #define OPT_WC 0 46 1.1 christos #else 47 1.1 christos #define OPT_WC (OPT_NOSAVE | OPT_NDISP) 48 1.1 christos #endif 49 1.1 christos 50 1.1 christos /* 51 1.1 christos * O'Reilly noted options and abbreviations are from "Learning the VI Editor", 52 1.1 christos * Fifth Edition, May 1992. There's no way of knowing what systems they are 53 1.1 christos * actually from. 54 1.1 christos * 55 1.1 christos * HPUX noted options and abbreviations are from "The Ultimate Guide to the 56 1.1 christos * VI and EX Text Editors", 1990. 57 1.2 christos * 58 1.2 christos * This list must be sorted... 59 1.1 christos */ 60 1.1 christos OPTLIST const optlist[] = { 61 1.1 christos /* O_ALTWERASE 4.4BSD */ 62 1.1 christos {L("altwerase"), f_altwerase, OPT_0BOOL, 0}, 63 1.1 christos /* O_AUTOINDENT 4BSD */ 64 1.1 christos {L("autoindent"), NULL, OPT_0BOOL, 0}, 65 1.1 christos /* O_AUTOPRINT 4BSD */ 66 1.1 christos {L("autoprint"), NULL, OPT_1BOOL, 0}, 67 1.1 christos /* O_AUTOWRITE 4BSD */ 68 1.1 christos {L("autowrite"), NULL, OPT_0BOOL, 0}, 69 1.1 christos /* O_BACKUP 4.4BSD */ 70 1.1 christos {L("backup"), NULL, OPT_STR, 0}, 71 1.1 christos /* O_BEAUTIFY 4BSD */ 72 1.1 christos {L("beautify"), NULL, OPT_0BOOL, 0}, 73 1.1 christos /* O_CDPATH 4.4BSD */ 74 1.1 christos {L("cdpath"), NULL, OPT_STR, 0}, 75 1.1 christos /* O_CEDIT 4.4BSD */ 76 1.1 christos {L("cedit"), NULL, OPT_STR, 0}, 77 1.1 christos /* O_COLUMNS 4.4BSD */ 78 1.1 christos {L("columns"), f_columns, OPT_NUM, OPT_NOSAVE}, 79 1.1 christos /* O_COMBINED */ 80 1.1 christos {L("combined"), NULL, OPT_0BOOL, OPT_NOSET|OPT_WC}, 81 1.1 christos /* O_COMMENT 4.4BSD */ 82 1.1 christos {L("comment"), NULL, OPT_0BOOL, 0}, 83 1.1 christos /* O_TMP_DIRECTORY 4BSD */ 84 1.1 christos {L("directory"), NULL, OPT_STR, 0}, 85 1.1 christos /* O_EDCOMPATIBLE 4BSD */ 86 1.1 christos {L("edcompatible"),NULL, OPT_0BOOL, 0}, 87 1.2 christos /* O_ERRORBELLS 4BSD */ 88 1.2 christos {L("errorbells"), NULL, OPT_0BOOL, 0}, 89 1.1 christos /* O_ESCAPETIME 4.4BSD */ 90 1.1 christos {L("escapetime"), NULL, OPT_NUM, 0}, 91 1.2 christos /* O_EXPANDTAB NetBSD 5.0 */ 92 1.2 christos {L("expandtab"), NULL, OPT_0BOOL, 0}, 93 1.1 christos /* O_EXRC System V (undocumented) */ 94 1.1 christos {L("exrc"), NULL, OPT_0BOOL, 0}, 95 1.1 christos /* O_EXTENDED 4.4BSD */ 96 1.1 christos {L("extended"), f_recompile, OPT_0BOOL, 0}, 97 1.1 christos /* O_FILEC 4.4BSD */ 98 1.1 christos {L("filec"), NULL, OPT_STR, 0}, 99 1.1 christos /* O_FILEENCODING */ 100 1.1 christos {L("fileencoding"),f_encoding, OPT_STR, OPT_WC}, 101 1.1 christos /* O_FLASH HPUX */ 102 1.1 christos {L("flash"), NULL, OPT_1BOOL, 0}, 103 1.4 rin /* O_GTAGSMODE FreeBSD/NetBSD */ 104 1.2 christos #ifdef GTAGS 105 1.2 christos {L("gtagsmode"),NULL, OPT_0BOOL, 0}, 106 1.4 rin #else 107 1.4 rin {L("gtagsmode"),NULL, OPT_0BOOL, OPT_NDISP|OPT_NOSAVE|OPT_NOSET}, 108 1.2 christos #endif 109 1.1 christos /* O_HARDTABS 4BSD */ 110 1.1 christos {L("hardtabs"), NULL, OPT_NUM, 0}, 111 1.1 christos /* O_ICLOWER 4.4BSD */ 112 1.1 christos {L("iclower"), f_recompile, OPT_0BOOL, 0}, 113 1.1 christos /* O_IGNORECASE 4BSD */ 114 1.1 christos {L("ignorecase"), f_recompile, OPT_0BOOL, 0}, 115 1.6 rin /* O_IMCTRL nvi-m17n/NetBSD */ 116 1.6 rin #ifdef IMCTRL 117 1.6 rin {L("imctrl"), f_imctrl, OPT_0BOOL, 0}, 118 1.6 rin #else 119 1.6 rin {L("imctrl"), NULL, OPT_0BOOL, OPT_NDISP|OPT_NOSAVE|OPT_NOSET}, 120 1.6 rin #endif 121 1.6 rin /* O_IMKEY nvi-m17n/NetBSD */ 122 1.6 rin #ifdef IMCTRL 123 1.6 rin {L("imkey"), NULL, OPT_STR, 0}, 124 1.6 rin #else 125 1.6 rin {L("imkey"), NULL, OPT_STR, OPT_NDISP|OPT_NOSAVE}, 126 1.6 rin #endif 127 1.1 christos /* O_INPUTENCODING */ 128 1.1 christos {L("inputencoding"),f_encoding, OPT_STR, OPT_WC}, 129 1.1 christos /* O_KEYTIME 4.4BSD */ 130 1.1 christos {L("keytime"), NULL, OPT_NUM, 0}, 131 1.1 christos /* O_LEFTRIGHT 4.4BSD */ 132 1.1 christos {L("leftright"), f_reformat, OPT_0BOOL, 0}, 133 1.1 christos /* O_LINES 4.4BSD */ 134 1.1 christos {L("lines"), f_lines, OPT_NUM, OPT_NOSAVE}, 135 1.1 christos /* O_LISP 4BSD 136 1.1 christos * XXX 137 1.1 christos * When the lisp option is implemented, delete the OPT_NOSAVE flag, 138 1.1 christos * so that :mkexrc dumps it. 139 1.1 christos */ 140 1.1 christos {L("lisp"), f_lisp, OPT_0BOOL, OPT_NOSAVE}, 141 1.1 christos /* O_LIST 4BSD */ 142 1.1 christos {L("list"), f_reformat, OPT_0BOOL, 0}, 143 1.1 christos /* O_LOCKFILES 4.4BSD 144 1.1 christos * XXX 145 1.1 christos * Locking isn't reliable enough over NFS to require it, in addition, 146 1.1 christos * it's a serious startup performance problem over some remote links. 147 1.1 christos */ 148 1.1 christos {L("lock"), NULL, OPT_1BOOL, 0}, 149 1.1 christos /* O_MAGIC 4BSD */ 150 1.1 christos {L("magic"), NULL, OPT_1BOOL, 0}, 151 1.2 christos /* O_MATCHCHARS netbsd 2.0 */ 152 1.2 christos {L("matchchars"), NULL, OPT_STR, OPT_PAIRS}, 153 1.1 christos /* O_MATCHTIME 4.4BSD */ 154 1.1 christos {L("matchtime"), NULL, OPT_NUM, 0}, 155 1.1 christos /* O_MESG 4BSD */ 156 1.1 christos {L("mesg"), NULL, OPT_1BOOL, 0}, 157 1.1 christos /* O_MODELINE 4BSD 158 1.1 christos * !!! 159 1.1 christos * This has been documented in historical systems as both "modeline" 160 1.1 christos * and as "modelines". Regardless of the name, this option represents 161 1.1 christos * a security problem of mammoth proportions, not to mention a stunning 162 1.1 christos * example of what your intro CS professor referred to as the perils of 163 1.1 christos * mixing code and data. Don't add it, or I will kill you. 164 1.1 christos */ 165 1.1 christos {L("modeline"), NULL, OPT_0BOOL, OPT_NOSET}, 166 1.1 christos /* O_MSGCAT 4.4BSD */ 167 1.1 christos {L("msgcat"), f_msgcat, OPT_STR, 0}, 168 1.1 christos /* O_NOPRINT 4.4BSD */ 169 1.1 christos {L("noprint"), f_print, OPT_STR, 0}, 170 1.1 christos /* O_NUMBER 4BSD */ 171 1.1 christos {L("number"), f_reformat, OPT_0BOOL, 0}, 172 1.1 christos /* O_OCTAL 4.4BSD */ 173 1.1 christos {L("octal"), f_print, OPT_0BOOL, 0}, 174 1.1 christos /* O_OPEN 4BSD */ 175 1.1 christos {L("open"), NULL, OPT_1BOOL, 0}, 176 1.1 christos /* O_OPTIMIZE 4BSD */ 177 1.1 christos {L("optimize"), NULL, OPT_1BOOL, 0}, 178 1.1 christos /* O_PARAGRAPHS 4BSD */ 179 1.2 christos {L("paragraphs"), NULL, OPT_STR, OPT_PAIRS}, 180 1.1 christos /* O_PATH 4.4BSD */ 181 1.1 christos {L("path"), NULL, OPT_STR, 0}, 182 1.1 christos /* O_PRINT 4.4BSD */ 183 1.1 christos {L("print"), f_print, OPT_STR, 0}, 184 1.1 christos /* O_PROMPT 4BSD */ 185 1.1 christos {L("prompt"), NULL, OPT_1BOOL, 0}, 186 1.1 christos /* O_READONLY 4BSD (undocumented) */ 187 1.1 christos {L("readonly"), f_readonly, OPT_0BOOL, OPT_ALWAYS}, 188 1.1 christos /* O_RECDIR 4.4BSD */ 189 1.1 christos {L("recdir"), NULL, OPT_STR, 0}, 190 1.1 christos /* O_REDRAW 4BSD */ 191 1.1 christos {L("redraw"), NULL, OPT_0BOOL, 0}, 192 1.1 christos /* O_REMAP 4BSD */ 193 1.1 christos {L("remap"), NULL, OPT_1BOOL, 0}, 194 1.1 christos /* O_REPORT 4BSD */ 195 1.1 christos {L("report"), NULL, OPT_NUM, 0}, 196 1.1 christos /* O_RULER 4.4BSD */ 197 1.1 christos {L("ruler"), NULL, OPT_0BOOL, 0}, 198 1.1 christos /* O_SCROLL 4BSD */ 199 1.1 christos {L("scroll"), NULL, OPT_NUM, 0}, 200 1.1 christos /* O_SEARCHINCR 4.4BSD */ 201 1.1 christos {L("searchincr"), NULL, OPT_0BOOL, 0}, 202 1.1 christos /* O_SECTIONS 4BSD */ 203 1.2 christos {L("sections"), NULL, OPT_STR, OPT_PAIRS}, 204 1.1 christos /* O_SECURE 4.4BSD */ 205 1.1 christos {L("secure"), NULL, OPT_0BOOL, OPT_NOUNSET}, 206 1.1 christos /* O_SHELL 4BSD */ 207 1.1 christos {L("shell"), NULL, OPT_STR, 0}, 208 1.1 christos /* O_SHELLMETA 4.4BSD */ 209 1.1 christos {L("shellmeta"), NULL, OPT_STR, 0}, 210 1.1 christos /* O_SHIFTWIDTH 4BSD */ 211 1.1 christos {L("shiftwidth"), NULL, OPT_NUM, OPT_NOZERO}, 212 1.1 christos /* O_SHOWMATCH 4BSD */ 213 1.1 christos {L("showmatch"), NULL, OPT_0BOOL, 0}, 214 1.1 christos /* O_SHOWMODE 4.4BSD */ 215 1.1 christos {L("showmode"), NULL, OPT_0BOOL, 0}, 216 1.1 christos /* O_SIDESCROLL 4.4BSD */ 217 1.1 christos {L("sidescroll"), NULL, OPT_NUM, OPT_NOZERO}, 218 1.1 christos /* O_SLOWOPEN 4BSD */ 219 1.1 christos {L("slowopen"), NULL, OPT_0BOOL, 0}, 220 1.1 christos /* O_SOURCEANY 4BSD (undocumented) 221 1.1 christos * !!! 222 1.1 christos * Historic vi, on startup, source'd $HOME/.exrc and ./.exrc, if they 223 1.1 christos * were owned by the user. The sourceany option was an undocumented 224 1.1 christos * feature of historic vi which permitted the startup source'ing of 225 1.1 christos * .exrc files the user didn't own. This is an obvious security problem, 226 1.1 christos * and we ignore the option. 227 1.1 christos */ 228 1.1 christos {L("sourceany"), NULL, OPT_0BOOL, OPT_NOSET}, 229 1.1 christos /* O_TABSTOP 4BSD */ 230 1.1 christos {L("tabstop"), f_reformat, OPT_NUM, OPT_NOZERO}, 231 1.1 christos /* O_TAGLENGTH 4BSD */ 232 1.1 christos {L("taglength"), NULL, OPT_NUM, 0}, 233 1.1 christos /* O_TAGS 4BSD */ 234 1.1 christos {L("tags"), NULL, OPT_STR, 0}, 235 1.1 christos /* O_TERM 4BSD 236 1.1 christos * !!! 237 1.1 christos * By default, the historic vi always displayed information about two 238 1.1 christos * options, redraw and term. Term seems sufficient. 239 1.1 christos */ 240 1.1 christos {L("term"), NULL, OPT_STR, OPT_ADISP|OPT_NOSAVE}, 241 1.1 christos /* O_TERSE 4BSD */ 242 1.1 christos {L("terse"), NULL, OPT_0BOOL, 0}, 243 1.1 christos /* O_TILDEOP 4.4BSD */ 244 1.1 christos {L("tildeop"), NULL, OPT_0BOOL, 0}, 245 1.1 christos /* O_TIMEOUT 4BSD (undocumented) */ 246 1.1 christos {L("timeout"), NULL, OPT_1BOOL, 0}, 247 1.1 christos /* O_TTYWERASE 4.4BSD */ 248 1.1 christos {L("ttywerase"), f_ttywerase, OPT_0BOOL, 0}, 249 1.1 christos /* O_VERBOSE 4.4BSD */ 250 1.1 christos {L("verbose"), NULL, OPT_0BOOL, 0}, 251 1.1 christos /* O_W1200 4BSD */ 252 1.1 christos {L("w1200"), f_w1200, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, 253 1.1 christos /* O_W300 4BSD */ 254 1.1 christos {L("w300"), f_w300, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, 255 1.1 christos /* O_W9600 4BSD */ 256 1.1 christos {L("w9600"), f_w9600, OPT_NUM, OPT_NDISP|OPT_NOSAVE}, 257 1.1 christos /* O_WARN 4BSD */ 258 1.1 christos {L("warn"), NULL, OPT_1BOOL, 0}, 259 1.1 christos /* O_WINDOW 4BSD */ 260 1.1 christos {L("window"), f_window, OPT_NUM, 0}, 261 1.1 christos /* O_WINDOWNAME 4BSD */ 262 1.1 christos {L("windowname"), NULL, OPT_0BOOL, 0}, 263 1.1 christos /* O_WRAPLEN 4.4BSD */ 264 1.1 christos {L("wraplen"), NULL, OPT_NUM, 0}, 265 1.1 christos /* O_WRAPMARGIN 4BSD */ 266 1.1 christos {L("wrapmargin"), NULL, OPT_NUM, 0}, 267 1.1 christos /* O_WRAPSCAN 4BSD */ 268 1.1 christos {L("wrapscan"), NULL, OPT_1BOOL, 0}, 269 1.1 christos /* O_WRITEANY 4BSD */ 270 1.1 christos {L("writeany"), NULL, OPT_0BOOL, 0}, 271 1.2 christos {NULL, NULL, OPT_NUM, 0}, 272 1.1 christos }; 273 1.1 christos 274 1.1 christos typedef struct abbrev { 275 1.2 christos const CHAR_T *name; 276 1.1 christos int offset; 277 1.1 christos } OABBREV; 278 1.1 christos 279 1.1 christos static OABBREV const abbrev[] = { 280 1.1 christos {L("ai"), O_AUTOINDENT}, /* 4BSD */ 281 1.1 christos {L("ap"), O_AUTOPRINT}, /* 4BSD */ 282 1.1 christos {L("aw"), O_AUTOWRITE}, /* 4BSD */ 283 1.1 christos {L("bf"), O_BEAUTIFY}, /* 4BSD */ 284 1.1 christos {L("co"), O_COLUMNS}, /* 4.4BSD */ 285 1.1 christos {L("dir"), O_TMP_DIRECTORY}, /* 4BSD */ 286 1.1 christos {L("eb"), O_ERRORBELLS}, /* 4BSD */ 287 1.1 christos {L("ed"), O_EDCOMPATIBLE}, /* 4BSD */ 288 1.2 christos {L("et"), O_EXPANDTAB}, /* NetBSD 5.0 */ 289 1.1 christos {L("ex"), O_EXRC}, /* System V (undocumented) */ 290 1.5 rin {L("fe"), O_FILEENCODING}, 291 1.2 christos #ifdef GTAGS 292 1.2 christos {L("gt"), O_GTAGSMODE}, /* FreeBSD, NetBSD */ 293 1.2 christos #endif 294 1.1 christos {L("ht"), O_HARDTABS}, /* 4BSD */ 295 1.1 christos {L("ic"), O_IGNORECASE}, /* 4BSD */ 296 1.1 christos {L("ie"), O_INPUTENCODING}, 297 1.1 christos {L("li"), O_LINES}, /* 4.4BSD */ 298 1.1 christos {L("modelines"), O_MODELINE}, /* HPUX */ 299 1.1 christos {L("nu"), O_NUMBER}, /* 4BSD */ 300 1.1 christos {L("opt"), O_OPTIMIZE}, /* 4BSD */ 301 1.1 christos {L("para"), O_PARAGRAPHS}, /* 4BSD */ 302 1.1 christos {L("re"), O_REDRAW}, /* O'Reilly */ 303 1.1 christos {L("ro"), O_READONLY}, /* 4BSD (undocumented) */ 304 1.1 christos {L("scr"), O_SCROLL}, /* 4BSD (undocumented) */ 305 1.1 christos {L("sect"), O_SECTIONS}, /* O'Reilly */ 306 1.1 christos {L("sh"), O_SHELL}, /* 4BSD */ 307 1.1 christos {L("slow"), O_SLOWOPEN}, /* 4BSD */ 308 1.1 christos {L("sm"), O_SHOWMATCH}, /* 4BSD */ 309 1.1 christos {L("smd"), O_SHOWMODE}, /* 4BSD */ 310 1.1 christos {L("sw"), O_SHIFTWIDTH}, /* 4BSD */ 311 1.1 christos {L("tag"), O_TAGS}, /* 4BSD (undocumented) */ 312 1.1 christos {L("tl"), O_TAGLENGTH}, /* 4BSD */ 313 1.1 christos {L("to"), O_TIMEOUT}, /* 4BSD (undocumented) */ 314 1.1 christos {L("ts"), O_TABSTOP}, /* 4BSD */ 315 1.1 christos {L("tty"), O_TERM}, /* 4BSD (undocumented) */ 316 1.1 christos {L("ttytype"), O_TERM}, /* 4BSD (undocumented) */ 317 1.1 christos {L("w"), O_WINDOW}, /* O'Reilly */ 318 1.1 christos {L("wa"), O_WRITEANY}, /* 4BSD */ 319 1.1 christos {L("wi"), O_WINDOW}, /* 4BSD (undocumented) */ 320 1.1 christos {L("wl"), O_WRAPLEN}, /* 4.4BSD */ 321 1.1 christos {L("wm"), O_WRAPMARGIN}, /* 4BSD */ 322 1.1 christos {L("ws"), O_WRAPSCAN}, /* 4BSD */ 323 1.2 christos {NULL, 0}, 324 1.1 christos }; 325 1.1 christos 326 1.1 christos /* 327 1.1 christos * opts_init -- 328 1.1 christos * Initialize some of the options. 329 1.1 christos * 330 1.1 christos * PUBLIC: int opts_init __P((SCR *, int *)); 331 1.1 christos */ 332 1.1 christos int 333 1.1 christos opts_init(SCR *sp, int *oargs) 334 1.1 christos { 335 1.1 christos ARGS *argv[2], a, b; 336 1.1 christos OPTLIST const *op; 337 1.1 christos u_long isset, v; 338 1.2 christos int cnt, optindx = 0; 339 1.1 christos char *s; 340 1.1 christos CHAR_T b2[1024]; 341 1.2 christos 342 1.2 christos if (sizeof optlist / sizeof optlist[0] - 1 != O_OPTIONCOUNT) { 343 1.2 christos fprintf(stderr, "vi: option table size error (%d != %d)\n", 344 1.2 christos (int)(sizeof optlist / sizeof optlist[0] - 1), 345 1.2 christos O_OPTIONCOUNT); 346 1.2 christos exit(1); 347 1.2 christos } 348 1.1 christos 349 1.1 christos a.bp = b2; 350 1.1 christos b.bp = NULL; 351 1.1 christos a.len = b.len = 0; 352 1.1 christos argv[0] = &a; 353 1.1 christos argv[1] = &b; 354 1.1 christos 355 1.1 christos /* Set numeric and string default values. */ 356 1.1 christos #define OI(indx, str) { \ 357 1.1 christos a.len = STRLEN(str); \ 358 1.2 christos if ((const CHAR_T*)str != b2)/* GCC puts strings in text-space. */\ 359 1.7 mrg (void)MEMMOVE(b2, str, a.len+1); \ 360 1.1 christos if (opts_set(sp, argv, NULL)) { \ 361 1.1 christos optindx = indx; \ 362 1.1 christos goto err; \ 363 1.1 christos } \ 364 1.1 christos } 365 1.1 christos /* 366 1.1 christos * Indirect global options to global space. Specifically, set up 367 1.1 christos * terminal, lines, columns first, they're used by other options. 368 1.1 christos * Note, don't set the flags until we've set up the indirection. 369 1.1 christos */ 370 1.1 christos if (o_set(sp, O_TERM, 0, NULL, GO_TERM)) 371 1.1 christos goto err; 372 1.1 christos F_SET(&sp->opts[O_TERM], OPT_GLOBAL); 373 1.1 christos if (o_set(sp, O_LINES, 0, NULL, GO_LINES)) 374 1.1 christos goto err; 375 1.1 christos F_SET(&sp->opts[O_LINES], OPT_GLOBAL); 376 1.1 christos if (o_set(sp, O_COLUMNS, 0, NULL, GO_COLUMNS)) 377 1.1 christos goto err; 378 1.1 christos F_SET(&sp->opts[O_COLUMNS], OPT_GLOBAL); 379 1.1 christos if (o_set(sp, O_SECURE, 0, NULL, GO_SECURE)) 380 1.1 christos goto err; 381 1.1 christos F_SET(&sp->opts[O_SECURE], OPT_GLOBAL); 382 1.1 christos 383 1.1 christos /* Initialize string values. */ 384 1.1 christos (void)SPRINTF(b2, SIZE(b2), 385 1.1 christos L("cdpath=%s"), (s = getenv("CDPATH")) == NULL ? ":" : s); 386 1.1 christos OI(O_CDPATH, b2); 387 1.1 christos 388 1.1 christos /* 389 1.1 christos * !!! 390 1.1 christos * Vi historically stored temporary files in /var/tmp. We store them 391 1.1 christos * in /tmp by default, hoping it's a memory based file system. There 392 1.1 christos * are two ways to change this -- the user can set either the directory 393 1.1 christos * option or the TMPDIR environmental variable. 394 1.1 christos */ 395 1.1 christos (void)SPRINTF(b2, SIZE(b2), 396 1.1 christos L("directory=%s"), (s = getenv("TMPDIR")) == NULL ? _PATH_TMP : s); 397 1.1 christos OI(O_TMP_DIRECTORY, b2); 398 1.1 christos OI(O_ESCAPETIME, L("escapetime=1")); 399 1.1 christos OI(O_KEYTIME, L("keytime=6")); 400 1.2 christos OI(O_MATCHCHARS, L("matchchars=()[]{}<>")); 401 1.1 christos OI(O_MATCHTIME, L("matchtime=7")); 402 1.1 christos (void)SPRINTF(b2, SIZE(b2), L("msgcat=%s"), _PATH_MSGCAT); 403 1.1 christos OI(O_MSGCAT, b2); 404 1.1 christos OI(O_REPORT, L("report=5")); 405 1.1 christos OI(O_PARAGRAPHS, L("paragraphs=IPLPPPQPP LIpplpipbp")); 406 1.1 christos (void)SPRINTF(b2, SIZE(b2), L("path=%s"), ""); 407 1.1 christos OI(O_PATH, b2); 408 1.1 christos (void)SPRINTF(b2, SIZE(b2), L("recdir=%s"), _PATH_PRESERVE); 409 1.1 christos OI(O_RECDIR, b2); 410 1.1 christos OI(O_SECTIONS, L("sections=NHSHH HUnhsh")); 411 1.1 christos (void)SPRINTF(b2, SIZE(b2), 412 1.1 christos L("shell=%s"), (s = getenv("SHELL")) == NULL ? _PATH_BSHELL : s); 413 1.1 christos OI(O_SHELL, b2); 414 1.1 christos OI(O_SHELLMETA, L("shellmeta=~{[*?$`'\"\\")); 415 1.1 christos OI(O_SHIFTWIDTH, L("shiftwidth=8")); 416 1.1 christos OI(O_SIDESCROLL, L("sidescroll=16")); 417 1.1 christos OI(O_TABSTOP, L("tabstop=8")); 418 1.1 christos (void)SPRINTF(b2, SIZE(b2), L("tags=%s"), _PATH_TAGS); 419 1.1 christos OI(O_TAGS, b2); 420 1.6 rin #ifdef IMCTRL 421 1.6 rin OI(O_IMKEY, L("imkey=/?aioAIO")); 422 1.6 rin #endif 423 1.1 christos 424 1.1 christos /* 425 1.1 christos * XXX 426 1.1 christos * Initialize O_SCROLL here, after term; initializing term should 427 1.1 christos * have created a LINES/COLUMNS value. 428 1.1 christos */ 429 1.1 christos if ((v = (O_VAL(sp, O_LINES) - 1) / 2) == 0) 430 1.1 christos v = 1; 431 1.1 christos (void)SPRINTF(b2, SIZE(b2), L("scroll=%ld"), v); 432 1.1 christos OI(O_SCROLL, b2); 433 1.1 christos 434 1.1 christos /* 435 1.1 christos * The default window option values are: 436 1.1 christos * 8 if baud rate <= 600 437 1.1 christos * 16 if baud rate <= 1200 438 1.1 christos * LINES - 1 if baud rate > 1200 439 1.1 christos * 440 1.1 christos * Note, the windows option code will correct any too-large value 441 1.1 christos * or when the O_LINES value is 1. 442 1.1 christos */ 443 1.1 christos if (sp->gp->scr_baud(sp, &v)) 444 1.1 christos return (1); 445 1.1 christos if (v <= 600) 446 1.1 christos v = 8; 447 1.1 christos else if (v <= 1200) 448 1.1 christos v = 16; 449 1.1 christos else if ((v = O_VAL(sp, O_LINES) - 1) == 0) 450 1.1 christos v = 1; 451 1.1 christos 452 1.1 christos (void)SPRINTF(b2, SIZE(b2), L("window=%lu"), v); 453 1.1 christos OI(O_WINDOW, b2); 454 1.1 christos 455 1.1 christos /* 456 1.1 christos * Set boolean default values, and copy all settings into the default 457 1.1 christos * information. OS_NOFREE is set, we're copying, not replacing. 458 1.1 christos */ 459 1.1 christos for (op = optlist, cnt = 0; op->name != NULL; ++op, ++cnt) 460 1.1 christos switch (op->type) { 461 1.1 christos case OPT_0BOOL: 462 1.1 christos break; 463 1.1 christos case OPT_1BOOL: 464 1.1 christos O_SET(sp, cnt); 465 1.1 christos O_D_SET(sp, cnt); 466 1.1 christos break; 467 1.1 christos case OPT_NUM: 468 1.1 christos o_set(sp, cnt, OS_DEF, NULL, O_VAL(sp, cnt)); 469 1.1 christos break; 470 1.1 christos case OPT_STR: 471 1.1 christos if (O_STR(sp, cnt) != NULL && o_set(sp, cnt, 472 1.1 christos OS_DEF | OS_NOFREE | OS_STRDUP, O_STR(sp, cnt), 0)) 473 1.1 christos goto err; 474 1.1 christos break; 475 1.1 christos default: 476 1.1 christos abort(); 477 1.1 christos } 478 1.1 christos 479 1.1 christos /* 480 1.1 christos * !!! 481 1.1 christos * Some options can be initialized by the command name or the 482 1.1 christos * command-line arguments. They don't set the default values, 483 1.1 christos * it's historic practice. 484 1.1 christos */ 485 1.1 christos for (; *oargs != -1; ++oargs) 486 1.1 christos OI(*oargs, optlist[*oargs].name); 487 1.1 christos #undef OI 488 1.1 christos 489 1.1 christos /* 490 1.1 christos * Inform the underlying screen of the initial values of the 491 1.1 christos * edit options. 492 1.1 christos */ 493 1.1 christos for (op = optlist, cnt = 0; op->name != NULL; ++op, ++cnt) { 494 1.1 christos isset = O_ISSET(sp, cnt); 495 1.1 christos (void)sp->gp->scr_optchange(sp, cnt, O_STR(sp, cnt), &isset); 496 1.1 christos } 497 1.1 christos return (0); 498 1.1 christos 499 1.2 christos err: msgq_wstr(sp, M_ERR, optlist[optindx].name, 500 1.2 christos "031|Unable to set default %s option"); 501 1.1 christos return (1); 502 1.1 christos } 503 1.1 christos 504 1.1 christos /* 505 1.1 christos * opts_set -- 506 1.1 christos * Change the values of one or more options. 507 1.1 christos * 508 1.2 christos * PUBLIC: int opts_set __P((SCR *, ARGS *[], const char *)); 509 1.1 christos */ 510 1.1 christos int 511 1.2 christos opts_set(SCR *sp, ARGS **argv, const char *usage) 512 1.1 christos { 513 1.1 christos enum optdisp disp; 514 1.1 christos enum nresult nret; 515 1.1 christos OPTLIST const *op; 516 1.1 christos OPTION *spo; 517 1.1 christos u_long isset, turnoff, value; 518 1.1 christos int ch, equals, nf, nf2, offset, qmark, rval; 519 1.2 christos CHAR_T *endp, *name, *p, *sep; 520 1.1 christos char *p2, *t2; 521 1.2 christos const char *np; 522 1.1 christos size_t nlen; 523 1.1 christos 524 1.1 christos disp = NO_DISPLAY; 525 1.1 christos for (rval = 0; argv[0]->len != 0; ++argv) { 526 1.1 christos /* 527 1.1 christos * The historic vi dumped the options for each occurrence of 528 1.1 christos * "all" in the set list. Puhleeze. 529 1.1 christos */ 530 1.1 christos if (!STRCMP(argv[0]->bp, L("all"))) { 531 1.1 christos disp = ALL_DISPLAY; 532 1.1 christos continue; 533 1.1 christos } 534 1.1 christos 535 1.1 christos /* Find equals sign or question mark. */ 536 1.1 christos for (sep = NULL, equals = qmark = 0, 537 1.1 christos p = name = argv[0]->bp; (ch = *p) != '\0'; ++p) 538 1.1 christos if (ch == '=' || ch == '?') { 539 1.1 christos if (p == name) { 540 1.1 christos if (usage != NULL) 541 1.1 christos msgq(sp, M_ERR, 542 1.1 christos "032|Usage: %s", usage); 543 1.1 christos return (1); 544 1.1 christos } 545 1.1 christos sep = p; 546 1.1 christos if (ch == '=') 547 1.1 christos equals = 1; 548 1.1 christos else 549 1.1 christos qmark = 1; 550 1.1 christos break; 551 1.1 christos } 552 1.1 christos 553 1.1 christos turnoff = 0; 554 1.1 christos op = NULL; 555 1.1 christos if (sep != NULL) 556 1.1 christos *sep++ = '\0'; 557 1.1 christos 558 1.1 christos /* Search for the name, then name without any leading "no". */ 559 1.1 christos if ((op = opts_search(name)) == NULL && 560 1.1 christos name[0] == L('n') && name[1] == L('o')) { 561 1.1 christos turnoff = 1; 562 1.1 christos name += 2; 563 1.1 christos op = opts_search(name); 564 1.1 christos } 565 1.1 christos if (op == NULL) { 566 1.1 christos opts_nomatch(sp, name); 567 1.1 christos rval = 1; 568 1.1 christos continue; 569 1.1 christos } 570 1.1 christos 571 1.1 christos /* Find current option values. */ 572 1.1 christos offset = op - optlist; 573 1.1 christos spo = sp->opts + offset; 574 1.1 christos 575 1.1 christos /* 576 1.1 christos * !!! 577 1.1 christos * Historically, the question mark could be a separate 578 1.1 christos * argument. 579 1.1 christos */ 580 1.1 christos if (!equals && !qmark && 581 1.1 christos argv[1]->len == 1 && argv[1]->bp[0] == '?') { 582 1.1 christos ++argv; 583 1.1 christos qmark = 1; 584 1.1 christos } 585 1.1 christos 586 1.1 christos /* Set name, value. */ 587 1.1 christos switch (op->type) { 588 1.1 christos case OPT_0BOOL: 589 1.1 christos case OPT_1BOOL: 590 1.1 christos /* Some options may not be reset. */ 591 1.1 christos if (F_ISSET(op, OPT_NOUNSET) && turnoff) { 592 1.1 christos msgq_wstr(sp, M_ERR, name, 593 1.1 christos "291|set: the %s option may not be turned off"); 594 1.1 christos rval = 1; 595 1.1 christos break; 596 1.1 christos } 597 1.1 christos 598 1.1 christos /* Some options may not be set. */ 599 1.1 christos if (F_ISSET(op, OPT_NOSET) && !turnoff) { 600 1.1 christos msgq_wstr(sp, M_ERR, name, 601 1.1 christos "313|set: the %s option may never be turned on"); 602 1.1 christos rval = 1; 603 1.1 christos break; 604 1.1 christos } 605 1.1 christos 606 1.1 christos if (equals) { 607 1.1 christos msgq_wstr(sp, M_ERR, name, 608 1.1 christos "034|set: [no]%s option doesn't take a value"); 609 1.1 christos rval = 1; 610 1.1 christos break; 611 1.1 christos } 612 1.1 christos if (qmark) { 613 1.1 christos if (!disp) 614 1.1 christos disp = SELECT_DISPLAY; 615 1.1 christos F_SET(spo, OPT_SELECTED); 616 1.1 christos break; 617 1.1 christos } 618 1.1 christos 619 1.1 christos /* 620 1.1 christos * Do nothing if the value is unchanged, the underlying 621 1.1 christos * functions can be expensive. 622 1.1 christos */ 623 1.1 christos isset = !turnoff; 624 1.2 christos if (!F_ISSET(op, OPT_ALWAYS)) { 625 1.1 christos if (isset) { 626 1.1 christos if (O_ISSET(sp, offset)) 627 1.1 christos break; 628 1.1 christos } else 629 1.1 christos if (!O_ISSET(sp, offset)) 630 1.1 christos break; 631 1.2 christos } 632 1.1 christos 633 1.1 christos /* Report to subsystems. */ 634 1.2 christos if ((op->func != NULL && 635 1.2 christos op->func(sp, spo, NULL, &isset)) || 636 1.1 christos ex_optchange(sp, offset, NULL, &isset) || 637 1.1 christos v_optchange(sp, offset, NULL, &isset) || 638 1.1 christos sp->gp->scr_optchange(sp, offset, NULL, &isset)) { 639 1.1 christos rval = 1; 640 1.1 christos break; 641 1.1 christos } 642 1.1 christos 643 1.1 christos /* Set the value. */ 644 1.1 christos if (isset) 645 1.1 christos O_SET(sp, offset); 646 1.1 christos else 647 1.1 christos O_CLR(sp, offset); 648 1.1 christos break; 649 1.1 christos case OPT_NUM: 650 1.1 christos if (turnoff) { 651 1.1 christos msgq_wstr(sp, M_ERR, name, 652 1.1 christos "035|set: %s option isn't a boolean"); 653 1.1 christos rval = 1; 654 1.1 christos break; 655 1.1 christos } 656 1.1 christos if (qmark || !equals) { 657 1.1 christos if (!disp) 658 1.1 christos disp = SELECT_DISPLAY; 659 1.1 christos F_SET(spo, OPT_SELECTED); 660 1.1 christos break; 661 1.1 christos } 662 1.1 christos 663 1.2 christos if (!ISDIGIT((UCHAR_T)sep[0])) 664 1.1 christos goto badnum; 665 1.1 christos if ((nret = 666 1.1 christos nget_uslong(sp, &value, sep, &endp, 10)) != NUM_OK) { 667 1.1 christos INT2CHAR(sp, name, STRLEN(name) + 1, 668 1.1 christos np, nlen); 669 1.1 christos p2 = msg_print(sp, np, &nf); 670 1.1 christos INT2CHAR(sp, sep, STRLEN(sep) + 1, 671 1.1 christos np, nlen); 672 1.1 christos t2 = msg_print(sp, np, &nf2); 673 1.1 christos switch (nret) { 674 1.1 christos case NUM_ERR: 675 1.1 christos msgq(sp, M_SYSERR, 676 1.1 christos "036|set: %s option: %s", p2, t2); 677 1.1 christos break; 678 1.1 christos case NUM_OVER: 679 1.1 christos msgq(sp, M_ERR, 680 1.1 christos "037|set: %s option: %s: value overflow", p2, t2); 681 1.1 christos break; 682 1.1 christos case NUM_OK: 683 1.1 christos case NUM_UNDER: 684 1.1 christos abort(); 685 1.1 christos } 686 1.1 christos if (nf) 687 1.1 christos FREE_SPACE(sp, p2, 0); 688 1.1 christos if (nf2) 689 1.1 christos FREE_SPACE(sp, t2, 0); 690 1.1 christos rval = 1; 691 1.1 christos break; 692 1.1 christos } 693 1.1 christos if (*endp && !ISBLANK(*endp)) { 694 1.1 christos badnum: INT2CHAR(sp, name, STRLEN(name) + 1, 695 1.1 christos np, nlen); 696 1.1 christos p2 = msg_print(sp, np, &nf); 697 1.1 christos INT2CHAR(sp, sep, STRLEN(sep) + 1, 698 1.1 christos np, nlen); 699 1.1 christos t2 = msg_print(sp, np, &nf2); 700 1.1 christos msgq(sp, M_ERR, 701 1.1 christos "038|set: %s option: %s is an illegal number", p2, t2); 702 1.1 christos if (nf) 703 1.1 christos FREE_SPACE(sp, p2, 0); 704 1.1 christos if (nf2) 705 1.1 christos FREE_SPACE(sp, t2, 0); 706 1.1 christos rval = 1; 707 1.1 christos break; 708 1.1 christos } 709 1.1 christos 710 1.1 christos /* Some options may never be set to zero. */ 711 1.1 christos if (F_ISSET(op, OPT_NOZERO) && value == 0) { 712 1.1 christos msgq_wstr(sp, M_ERR, name, 713 1.1 christos "314|set: the %s option may never be set to 0"); 714 1.1 christos rval = 1; 715 1.1 christos break; 716 1.1 christos } 717 1.1 christos 718 1.1 christos /* 719 1.1 christos * Do nothing if the value is unchanged, the underlying 720 1.1 christos * functions can be expensive. 721 1.1 christos */ 722 1.1 christos if (!F_ISSET(op, OPT_ALWAYS) && 723 1.1 christos O_VAL(sp, offset) == value) 724 1.1 christos break; 725 1.1 christos 726 1.1 christos /* Report to subsystems. */ 727 1.1 christos INT2CHAR(sp, sep, STRLEN(sep) + 1, np, nlen); 728 1.2 christos if ((op->func != NULL && 729 1.2 christos op->func(sp, spo, np, &value)) || 730 1.1 christos ex_optchange(sp, offset, np, &value) || 731 1.1 christos v_optchange(sp, offset, np, &value) || 732 1.1 christos sp->gp->scr_optchange(sp, offset, np, &value)) { 733 1.1 christos rval = 1; 734 1.1 christos break; 735 1.1 christos } 736 1.1 christos 737 1.1 christos /* Set the value. */ 738 1.1 christos if (o_set(sp, offset, 0, NULL, value)) 739 1.1 christos rval = 1; 740 1.1 christos break; 741 1.1 christos case OPT_STR: 742 1.1 christos if (turnoff) { 743 1.1 christos msgq_wstr(sp, M_ERR, name, 744 1.1 christos "039|set: %s option isn't a boolean"); 745 1.1 christos rval = 1; 746 1.1 christos break; 747 1.1 christos } 748 1.1 christos if (qmark || !equals) { 749 1.1 christos if (!disp) 750 1.1 christos disp = SELECT_DISPLAY; 751 1.1 christos F_SET(spo, OPT_SELECTED); 752 1.1 christos break; 753 1.1 christos } 754 1.1 christos 755 1.2 christos /* Check for strings that must have even length */ 756 1.2 christos if (F_ISSET(op, OPT_PAIRS) && STRLEN(sep) & 1) { 757 1.2 christos msgq_wstr(sp, M_ERR, name, 758 1.2 christos "047|set: the %s option must be in two character groups"); 759 1.2 christos rval = 1; 760 1.2 christos break; 761 1.2 christos } 762 1.2 christos 763 1.1 christos /* 764 1.1 christos * Do nothing if the value is unchanged, the underlying 765 1.1 christos * functions can be expensive. 766 1.1 christos */ 767 1.1 christos INT2CHAR(sp, sep, STRLEN(sep) + 1, np, nlen); 768 1.1 christos if (!F_ISSET(op, OPT_ALWAYS) && 769 1.1 christos O_STR(sp, offset) != NULL && 770 1.1 christos !strcmp(O_STR(sp, offset), np)) 771 1.1 christos break; 772 1.1 christos 773 1.1 christos /* Report to subsystems. */ 774 1.2 christos if ((op->func != NULL && 775 1.2 christos op->func(sp, spo, np, NULL)) || 776 1.1 christos ex_optchange(sp, offset, np, NULL) || 777 1.1 christos v_optchange(sp, offset, np, NULL) || 778 1.1 christos sp->gp->scr_optchange(sp, offset, np, NULL)) { 779 1.1 christos rval = 1; 780 1.1 christos break; 781 1.1 christos } 782 1.1 christos 783 1.1 christos /* Set the value. */ 784 1.1 christos if (o_set(sp, offset, OS_STRDUP, np, 0)) 785 1.1 christos rval = 1; 786 1.1 christos break; 787 1.1 christos default: 788 1.1 christos abort(); 789 1.1 christos } 790 1.1 christos } 791 1.1 christos if (disp != NO_DISPLAY) 792 1.1 christos opts_dump(sp, disp); 793 1.1 christos return (rval); 794 1.1 christos } 795 1.1 christos 796 1.1 christos /* 797 1.1 christos * o_set -- 798 1.1 christos * Set an option's value. 799 1.1 christos * 800 1.2 christos * PUBLIC: int o_set __P((SCR *, int, u_int, const char *, u_long)); 801 1.1 christos */ 802 1.1 christos int 803 1.2 christos o_set(SCR *sp, int opt, u_int flags, const char *str, u_long val) 804 1.1 christos { 805 1.1 christos OPTION *op; 806 1.1 christos 807 1.1 christos /* Set a pointer to the options area. */ 808 1.1 christos op = F_ISSET(&sp->opts[opt], OPT_GLOBAL) ? 809 1.1 christos &sp->gp->opts[sp->opts[opt].o_cur.val] : &sp->opts[opt]; 810 1.1 christos 811 1.1 christos /* Copy the string, if requested. */ 812 1.1 christos if (LF_ISSET(OS_STRDUP) && (str = strdup(str)) == NULL) { 813 1.1 christos msgq(sp, M_SYSERR, NULL); 814 1.1 christos return (1); 815 1.1 christos } 816 1.1 christos 817 1.1 christos /* Free the previous string, if requested, and set the value. */ 818 1.1 christos if LF_ISSET(OS_DEF) 819 1.1 christos if (LF_ISSET(OS_STR | OS_STRDUP)) { 820 1.1 christos if (!LF_ISSET(OS_NOFREE) && op->o_def.str != NULL) 821 1.2 christos free(__UNCONST(op->o_def.str)); 822 1.1 christos op->o_def.str = str; 823 1.1 christos } else 824 1.1 christos op->o_def.val = val; 825 1.1 christos else 826 1.1 christos if (LF_ISSET(OS_STR | OS_STRDUP)) { 827 1.1 christos if (!LF_ISSET(OS_NOFREE) && op->o_cur.str != NULL) 828 1.2 christos free(__UNCONST(op->o_cur.str)); 829 1.1 christos op->o_cur.str = str; 830 1.1 christos } else 831 1.1 christos op->o_cur.val = val; 832 1.1 christos return (0); 833 1.1 christos } 834 1.1 christos 835 1.1 christos /* 836 1.1 christos * opts_empty -- 837 1.1 christos * Return 1 if the string option is invalid, 0 if it's OK. 838 1.1 christos * 839 1.1 christos * PUBLIC: int opts_empty __P((SCR *, int, int)); 840 1.1 christos */ 841 1.1 christos int 842 1.1 christos opts_empty(SCR *sp, int off, int silent) 843 1.1 christos { 844 1.2 christos const char *p; 845 1.1 christos 846 1.1 christos if ((p = O_STR(sp, off)) == NULL || p[0] == '\0') { 847 1.1 christos if (!silent) 848 1.1 christos msgq_wstr(sp, M_ERR, optlist[off].name, 849 1.1 christos "305|No %s edit option specified"); 850 1.1 christos return (1); 851 1.1 christos } 852 1.1 christos return (0); 853 1.1 christos } 854 1.1 christos 855 1.1 christos /* 856 1.1 christos * opts_dump -- 857 1.1 christos * List the current values of selected options. 858 1.1 christos * 859 1.1 christos * PUBLIC: void opts_dump __P((SCR *, enum optdisp)); 860 1.1 christos */ 861 1.1 christos void 862 1.1 christos opts_dump(SCR *sp, enum optdisp type) 863 1.1 christos { 864 1.1 christos OPTLIST const *op; 865 1.1 christos int base, b_num, cnt, col, colwidth, curlen, s_num; 866 1.1 christos int numcols, numrows, row; 867 1.1 christos int b_op[O_OPTIONCOUNT], s_op[O_OPTIONCOUNT]; 868 1.1 christos char nbuf[20]; 869 1.1 christos 870 1.1 christos /* 871 1.1 christos * Options are output in two groups -- those that fit in a column and 872 1.1 christos * those that don't. Output is done on 6 character "tab" boundaries 873 1.1 christos * for no particular reason. (Since we don't output tab characters, 874 1.1 christos * we can ignore the terminal's tab settings.) Ignore the user's tab 875 1.1 christos * setting because we have no idea how reasonable it is. 876 1.1 christos * 877 1.1 christos * Find a column width we can live with, testing from 10 columns to 1. 878 1.1 christos */ 879 1.1 christos for (numcols = 10; numcols > 1; --numcols) { 880 1.1 christos colwidth = sp->cols / numcols & ~(STANDARD_TAB - 1); 881 1.1 christos if (colwidth >= 10) { 882 1.1 christos colwidth = 883 1.1 christos (colwidth + STANDARD_TAB) & ~(STANDARD_TAB - 1); 884 1.1 christos numcols = sp->cols / colwidth; 885 1.1 christos break; 886 1.1 christos } 887 1.1 christos colwidth = 0; 888 1.1 christos } 889 1.1 christos 890 1.1 christos /* 891 1.1 christos * Get the set of options to list, entering them into 892 1.1 christos * the column list or the overflow list. 893 1.1 christos */ 894 1.1 christos for (b_num = s_num = 0, op = optlist; op->name != NULL; ++op) { 895 1.1 christos cnt = op - optlist; 896 1.1 christos 897 1.1 christos /* If OPT_NDISP set, it's never displayed. */ 898 1.1 christos if (F_ISSET(op, OPT_NDISP)) 899 1.1 christos continue; 900 1.1 christos 901 1.1 christos switch (type) { 902 1.1 christos case ALL_DISPLAY: /* Display all. */ 903 1.1 christos break; 904 1.1 christos case CHANGED_DISPLAY: /* Display changed. */ 905 1.1 christos /* If OPT_ADISP set, it's always "changed". */ 906 1.1 christos if (F_ISSET(op, OPT_ADISP)) 907 1.1 christos break; 908 1.1 christos switch (op->type) { 909 1.1 christos case OPT_0BOOL: 910 1.1 christos case OPT_1BOOL: 911 1.1 christos case OPT_NUM: 912 1.1 christos if (O_VAL(sp, cnt) == O_D_VAL(sp, cnt)) 913 1.1 christos continue; 914 1.1 christos break; 915 1.1 christos case OPT_STR: 916 1.1 christos if (O_STR(sp, cnt) == O_D_STR(sp, cnt) || 917 1.2 christos (O_D_STR(sp, cnt) != NULL && 918 1.2 christos !strcmp(O_STR(sp, cnt), O_D_STR(sp, cnt)))) 919 1.1 christos continue; 920 1.1 christos break; 921 1.1 christos } 922 1.1 christos break; 923 1.1 christos case SELECT_DISPLAY: /* Display selected. */ 924 1.1 christos if (!F_ISSET(&sp->opts[cnt], OPT_SELECTED)) 925 1.1 christos continue; 926 1.1 christos break; 927 1.1 christos default: 928 1.1 christos case NO_DISPLAY: 929 1.1 christos abort(); 930 1.1 christos } 931 1.1 christos F_CLR(&sp->opts[cnt], OPT_SELECTED); 932 1.1 christos 933 1.1 christos curlen = STRLEN(op->name); 934 1.1 christos switch (op->type) { 935 1.1 christos case OPT_0BOOL: 936 1.1 christos case OPT_1BOOL: 937 1.1 christos if (!O_ISSET(sp, cnt)) 938 1.1 christos curlen += 2; 939 1.1 christos break; 940 1.1 christos case OPT_NUM: 941 1.1 christos (void)snprintf(nbuf, 942 1.1 christos sizeof(nbuf), "%ld", O_VAL(sp, cnt)); 943 1.1 christos curlen += strlen(nbuf); 944 1.1 christos break; 945 1.1 christos case OPT_STR: 946 1.1 christos if (O_STR(sp, cnt) != NULL) 947 1.1 christos curlen += strlen(O_STR(sp, cnt)); 948 1.1 christos curlen += 3; 949 1.1 christos break; 950 1.1 christos } 951 1.1 christos /* Offset by 2 so there's a gap. */ 952 1.1 christos if (curlen <= colwidth - 2) 953 1.1 christos s_op[s_num++] = cnt; 954 1.1 christos else 955 1.1 christos b_op[b_num++] = cnt; 956 1.1 christos } 957 1.1 christos 958 1.1 christos if (s_num > 0) { 959 1.1 christos /* Figure out the number of rows. */ 960 1.1 christos if (s_num > numcols) { 961 1.1 christos numrows = s_num / numcols; 962 1.1 christos if (s_num % numcols) 963 1.1 christos ++numrows; 964 1.1 christos } else 965 1.1 christos numrows = 1; 966 1.1 christos 967 1.1 christos /* Display the options in sorted order. */ 968 1.1 christos for (row = 0; row < numrows;) { 969 1.1 christos for (base = row, col = 0; col < numcols; ++col) { 970 1.1 christos cnt = opts_print(sp, &optlist[s_op[base]]); 971 1.1 christos if ((base += numrows) >= s_num) 972 1.1 christos break; 973 1.1 christos (void)ex_printf(sp, "%*s", 974 1.1 christos (int)(colwidth - cnt), ""); 975 1.1 christos } 976 1.1 christos if (++row < numrows || b_num) 977 1.1 christos (void)ex_puts(sp, "\n"); 978 1.1 christos } 979 1.1 christos } 980 1.1 christos 981 1.1 christos for (row = 0; row < b_num;) { 982 1.1 christos (void)opts_print(sp, &optlist[b_op[row]]); 983 1.1 christos if (++row < b_num) 984 1.1 christos (void)ex_puts(sp, "\n"); 985 1.1 christos } 986 1.1 christos (void)ex_puts(sp, "\n"); 987 1.1 christos } 988 1.1 christos 989 1.1 christos /* 990 1.1 christos * opts_print -- 991 1.1 christos * Print out an option. 992 1.1 christos */ 993 1.1 christos static int 994 1.1 christos opts_print(SCR *sp, const OPTLIST *op) 995 1.1 christos { 996 1.1 christos int curlen, offset; 997 1.1 christos 998 1.1 christos curlen = 0; 999 1.1 christos offset = op - optlist; 1000 1.1 christos switch (op->type) { 1001 1.1 christos case OPT_0BOOL: 1002 1.1 christos case OPT_1BOOL: 1003 1.1 christos curlen += ex_printf(sp, 1004 1.1 christos "%s"WS, O_ISSET(sp, offset) ? "" : "no", op->name); 1005 1.1 christos break; 1006 1.1 christos case OPT_NUM: 1007 1.1 christos curlen += ex_printf(sp, WS"=%ld", op->name, O_VAL(sp, offset)); 1008 1.1 christos break; 1009 1.1 christos case OPT_STR: 1010 1.1 christos curlen += ex_printf(sp, WS"=\"%s\"", op->name, 1011 1.1 christos O_STR(sp, offset) == NULL ? "" : O_STR(sp, offset)); 1012 1.1 christos break; 1013 1.1 christos } 1014 1.1 christos return (curlen); 1015 1.1 christos } 1016 1.1 christos 1017 1.1 christos /* 1018 1.1 christos * opts_save -- 1019 1.1 christos * Write the current configuration to a file. 1020 1.1 christos * 1021 1.1 christos * PUBLIC: int opts_save __P((SCR *, FILE *)); 1022 1.1 christos */ 1023 1.1 christos int 1024 1.1 christos opts_save(SCR *sp, FILE *fp) 1025 1.1 christos { 1026 1.1 christos OPTLIST const *op; 1027 1.2 christos CHAR_T ch; 1028 1.2 christos const CHAR_T *p; 1029 1.2 christos char nch; 1030 1.2 christos const char *np; 1031 1.1 christos int cnt; 1032 1.1 christos 1033 1.1 christos for (op = optlist; op->name != NULL; ++op) { 1034 1.1 christos if (F_ISSET(op, OPT_NOSAVE)) 1035 1.1 christos continue; 1036 1.1 christos cnt = op - optlist; 1037 1.1 christos switch (op->type) { 1038 1.1 christos case OPT_0BOOL: 1039 1.1 christos case OPT_1BOOL: 1040 1.1 christos if (O_ISSET(sp, cnt)) 1041 1.1 christos (void)fprintf(fp, "set "WS"\n", op->name); 1042 1.1 christos else 1043 1.1 christos (void)fprintf(fp, "set no"WS"\n", op->name); 1044 1.1 christos break; 1045 1.1 christos case OPT_NUM: 1046 1.1 christos (void)fprintf(fp, 1047 1.1 christos "set "WS"=%-3ld\n", op->name, O_VAL(sp, cnt)); 1048 1.1 christos break; 1049 1.1 christos case OPT_STR: 1050 1.1 christos if (O_STR(sp, cnt) == NULL) 1051 1.1 christos break; 1052 1.1 christos (void)fprintf(fp, "set "); 1053 1.1 christos for (p = op->name; (ch = *p) != L('\0'); ++p) { 1054 1.1 christos if (ISBLANK(ch) || ch == L('\\')) 1055 1.1 christos (void)putc('\\', fp); 1056 1.1 christos fprintf(fp, WC, ch); 1057 1.1 christos } 1058 1.1 christos (void)putc('=', fp); 1059 1.1 christos for (np = O_STR(sp, cnt); (nch = *np) != '\0'; ++np) { 1060 1.2 christos if (isblank((unsigned char)nch) || nch == '\\') 1061 1.1 christos (void)putc('\\', fp); 1062 1.1 christos (void)putc(nch, fp); 1063 1.1 christos } 1064 1.1 christos (void)putc('\n', fp); 1065 1.1 christos break; 1066 1.1 christos } 1067 1.1 christos if (ferror(fp)) { 1068 1.1 christos msgq(sp, M_SYSERR, NULL); 1069 1.1 christos return (1); 1070 1.1 christos } 1071 1.1 christos } 1072 1.1 christos return (0); 1073 1.1 christos } 1074 1.1 christos 1075 1.1 christos /* 1076 1.1 christos * opts_search -- 1077 1.1 christos * Search for an option. 1078 1.1 christos * 1079 1.2 christos * PUBLIC: OPTLIST const *opts_search __P((const CHAR_T *)); 1080 1.1 christos */ 1081 1.1 christos OPTLIST const * 1082 1.2 christos opts_search(const CHAR_T *name) 1083 1.1 christos { 1084 1.1 christos OPTLIST const *op, *found; 1085 1.1 christos OABBREV atmp, *ap; 1086 1.1 christos OPTLIST otmp; 1087 1.1 christos size_t len; 1088 1.1 christos 1089 1.1 christos /* Check list of abbreviations. */ 1090 1.1 christos atmp.name = name; 1091 1.1 christos if ((ap = bsearch(&atmp, abbrev, sizeof(abbrev) / sizeof(OABBREV) - 1, 1092 1.1 christos sizeof(OABBREV), opts_abbcmp)) != NULL) 1093 1.1 christos return (optlist + ap->offset); 1094 1.1 christos 1095 1.1 christos /* Check list of options. */ 1096 1.1 christos otmp.name = name; 1097 1.1 christos if ((op = bsearch(&otmp, optlist, sizeof(optlist) / sizeof(OPTLIST) - 1, 1098 1.1 christos sizeof(OPTLIST), opts_cmp)) != NULL) 1099 1.1 christos return (op); 1100 1.1 christos 1101 1.1 christos /* 1102 1.1 christos * Check to see if the name is the prefix of one (and only one) 1103 1.1 christos * option. If so, return the option. 1104 1.1 christos */ 1105 1.1 christos len = STRLEN(name); 1106 1.1 christos for (found = NULL, op = optlist; op->name != NULL; ++op) { 1107 1.1 christos if (op->name[0] < name[0]) 1108 1.1 christos continue; 1109 1.1 christos if (op->name[0] > name[0]) 1110 1.1 christos break; 1111 1.1 christos if (!MEMCMP(op->name, name, len)) { 1112 1.1 christos if (found != NULL) 1113 1.1 christos return (NULL); 1114 1.1 christos found = op; 1115 1.1 christos } 1116 1.1 christos } 1117 1.1 christos return (found); 1118 1.1 christos } 1119 1.1 christos 1120 1.1 christos /* 1121 1.1 christos * opts_nomatch -- 1122 1.1 christos * Standard nomatch error message for options. 1123 1.1 christos * 1124 1.2 christos * PUBLIC: void opts_nomatch __P((SCR *, const CHAR_T *)); 1125 1.1 christos */ 1126 1.1 christos void 1127 1.2 christos opts_nomatch(SCR *sp, const CHAR_T *name) 1128 1.1 christos { 1129 1.1 christos msgq_wstr(sp, M_ERR, name, 1130 1.1 christos "033|set: no %s option: 'set all' gives all option values"); 1131 1.1 christos } 1132 1.1 christos 1133 1.1 christos static int 1134 1.1 christos opts_abbcmp(const void *a, const void *b) 1135 1.1 christos { 1136 1.2 christos return(STRCMP(((const OABBREV *)a)->name, ((const OABBREV *)b)->name)); 1137 1.1 christos } 1138 1.1 christos 1139 1.1 christos static int 1140 1.1 christos opts_cmp(const void *a, const void *b) 1141 1.1 christos { 1142 1.2 christos return(STRCMP(((const OPTLIST *)a)->name, ((const OPTLIST *)b)->name)); 1143 1.1 christos } 1144 1.1 christos 1145 1.1 christos /* 1146 1.1 christos * opts_copy -- 1147 1.1 christos * Copy a screen's OPTION array. 1148 1.1 christos * 1149 1.1 christos * PUBLIC: int opts_copy __P((SCR *, SCR *)); 1150 1.1 christos */ 1151 1.1 christos int 1152 1.1 christos opts_copy(SCR *orig, SCR *sp) 1153 1.1 christos { 1154 1.1 christos int cnt, rval; 1155 1.1 christos 1156 1.1 christos /* Copy most everything without change. */ 1157 1.1 christos memcpy(sp->opts, orig->opts, sizeof(orig->opts)); 1158 1.1 christos 1159 1.1 christos /* Copy the string edit options. */ 1160 1.1 christos for (cnt = rval = 0; cnt < O_OPTIONCOUNT; ++cnt) { 1161 1.1 christos if (optlist[cnt].type != OPT_STR || 1162 1.1 christos F_ISSET(&sp->opts[cnt], OPT_GLOBAL)) 1163 1.1 christos continue; 1164 1.1 christos /* 1165 1.1 christos * If never set, or already failed, NULL out the entries -- 1166 1.1 christos * have to continue after failure, otherwise would have two 1167 1.1 christos * screens referencing the same memory. 1168 1.1 christos */ 1169 1.1 christos if (rval || O_STR(sp, cnt) == NULL) { 1170 1.1 christos o_set(sp, cnt, OS_NOFREE | OS_STR, NULL, 0); 1171 1.1 christos o_set(sp, cnt, OS_DEF | OS_NOFREE | OS_STR, NULL, 0); 1172 1.1 christos continue; 1173 1.1 christos } 1174 1.1 christos 1175 1.1 christos /* Copy the current string. */ 1176 1.1 christos if (o_set(sp, cnt, OS_NOFREE | OS_STRDUP, O_STR(sp, cnt), 0)) { 1177 1.1 christos o_set(sp, cnt, OS_DEF | OS_NOFREE | OS_STR, NULL, 0); 1178 1.1 christos goto nomem; 1179 1.1 christos } 1180 1.1 christos 1181 1.1 christos /* Copy the default string. */ 1182 1.1 christos if (O_D_STR(sp, cnt) != NULL && o_set(sp, cnt, 1183 1.1 christos OS_DEF | OS_NOFREE | OS_STRDUP, O_D_STR(sp, cnt), 0)) { 1184 1.1 christos nomem: msgq(orig, M_SYSERR, NULL); 1185 1.1 christos rval = 1; 1186 1.1 christos } 1187 1.1 christos } 1188 1.1 christos return (rval); 1189 1.1 christos } 1190 1.1 christos 1191 1.1 christos /* 1192 1.1 christos * opts_free -- 1193 1.1 christos * Free all option strings 1194 1.1 christos * 1195 1.1 christos * PUBLIC: void opts_free __P((SCR *)); 1196 1.1 christos */ 1197 1.1 christos void 1198 1.1 christos opts_free(SCR *sp) 1199 1.1 christos { 1200 1.1 christos int cnt; 1201 1.1 christos 1202 1.1 christos for (cnt = 0; cnt < O_OPTIONCOUNT; ++cnt) { 1203 1.1 christos if (optlist[cnt].type != OPT_STR || 1204 1.1 christos F_ISSET(&sp->opts[cnt], OPT_GLOBAL)) 1205 1.1 christos continue; 1206 1.1 christos if (O_STR(sp, cnt) != NULL) 1207 1.2 christos free(__UNCONST(O_STR(sp, cnt))); 1208 1.1 christos if (O_D_STR(sp, cnt) != NULL) 1209 1.2 christos free(__UNCONST(O_D_STR(sp, cnt))); 1210 1.1 christos } 1211 1.1 christos } 1212