home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / elvis184.zip / src / opts.c < prev    next >
C/C++ Source or Header  |  1995-05-26  |  23KB  |  1,121 lines

  1. /* opts.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    1500 SW Park #326
  6.  *    Portland OR, 97201
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* modified by TJH and FEB to port to VMS */
  12.  
  13.  
  14. /* This file contains the code that manages the run-time options -- The 
  15.  * values that can be modified via the "set" command.
  16.  */
  17.  
  18. #include "config.h"
  19. #include "vi.h"
  20. #include "ctype.h"
  21. #include <stdio.h>
  22. #if VMS
  23. # include <ssdef.h>
  24. # include <iodef.h>
  25. # include <descrip.h>
  26. # include <tt2def.h>
  27. #endif
  28. #ifndef NULL
  29. #define NULL (char *)0
  30. #endif
  31.  
  32. /* maximum width to permit for strings, including ="" */
  33. #define MAXWIDTH 20
  34.  
  35. /* These are the default values of all options */
  36. char    o_autoindent[1] =    {FALSE};
  37. char    o_autoprint[1] =    {TRUE};
  38. char    o_autotab[1] =        {TRUE};
  39. char    o_autowrite[1] =     {FALSE};
  40. char    o_columns[3] =        {80, 32, ~0};
  41. char    o_directory[30] =    TMPDIR;
  42. char    o_edcompatible[1] =    {FALSE};
  43. char    o_equalprg[80] =    {"fmt"};
  44. char    o_errorbells[1] =    {TRUE};
  45. char    o_exrefresh[1] =    {TRUE};
  46. char    o_ignorecase[1] =    {FALSE};
  47. char    o_keytime[3] =        {2, 0, 50};
  48. char    o_keywordprg[80] =    {KEYWORDPRG};
  49. char    o_lines[3] =        {25, 2, 96};
  50. char    o_list[1] =        {FALSE};
  51. char    o_number[1] =        {FALSE};
  52. char    o_readonly[1] =        {FALSE};
  53. char    o_remap[1] =        {TRUE};
  54. char    o_report[3] =        {5, 1, 127};
  55. char    o_scroll[3] =        {12, 1, 127};
  56. char    o_shell[60] =        SHELL;
  57. char    o_shiftwidth[3] =    {8, 1, ~0};
  58. char    o_sidescroll[3] =    {8, 1, 40};
  59. char    o_sync[1] =        {NEEDSYNC};
  60. char    o_tabstop[3] =        {8, 1, 40};
  61. char    o_term[30] =        "?";
  62. char    o_flash[1] =        {TRUE};
  63. char    o_warn[1] =        {TRUE};
  64. char    o_wrapscan[1] =        {TRUE};
  65.  
  66. #ifndef CRUNCH
  67. char    o_beautify[1] =        {FALSE};
  68. char    o_exrc[1] =        {FALSE};
  69. char    o_mesg[1] =        {TRUE};
  70. char    o_more[1] =        {TRUE};
  71. char    o_nearscroll[3] =    {15, 0, ~0};
  72. char    o_newfile[1] =        {FALSE};
  73. char    o_novice[1] =        {FALSE};
  74. char    o_optimize[1] =        {FALSE};
  75. char    o_prompt[1] =        {TRUE};
  76. char    o_taglength[3] =    {0, 0, 30};
  77. char    o_tags[256] =        {"tags"};
  78. char    o_terse[1] =        {FALSE};
  79. char    o_window[3] =        {0, 0, ~0};
  80. char    o_wrapmargin[3] =    {0, 0, ~0};
  81. char    o_writeany[1] =        {FALSE};
  82. #endif
  83.  
  84. #ifndef NO_ERRLIST
  85. char    o_cc[30] =        {CC_COMMAND};
  86. char    o_make[30] =        {MAKE_COMMAND};
  87. #endif
  88.  
  89. #ifndef NO_CHARATTR
  90. char    o_charattr[1] =        {FALSE};
  91. #endif
  92.  
  93. #ifndef NO_DIGRAPH
  94. char    o_digraph[1] =        {FALSE};
  95. char    o_flipcase[80]
  96. # ifdef CS_IBMPC
  97.     = {"\207\200\201\232\202\220\204\216\206\217\221\222\224\231\244\245\233\235"}
  98. # endif
  99. # ifdef CS_LATIN1
  100.     /* initialized by initopts() */
  101. # endif
  102.     ;
  103. #endif
  104.  
  105. #ifndef NO_SENTENCE
  106. char    o_hideformat[1] =    {FALSE};
  107. #endif
  108.  
  109. #ifndef NO_EXTENSIONS
  110. char    o_inputmode[1] =    {FALSE};
  111. char    o_keepanon[1] =        {FALSE};
  112. char    o_ruler[1] =        {FALSE};
  113. #endif
  114.  
  115. #ifndef NO_MAGIC
  116. char    o_magic[1] =        {TRUE};
  117. #endif
  118.  
  119. #ifndef NO_MODELINES
  120. char    o_modelines[1] =    {FALSE};
  121. #endif
  122.  
  123. #ifndef NO_SENTENCE
  124. char    o_paragraphs[30] =    "PPppIPLPQP";
  125. char    o_sections[30] =    "NHSHSSSEse";
  126. #endif
  127.  
  128. #if MSDOS
  129. char    o_pcbios[1] =        {TRUE};
  130. char    o_controlz[1] =        {TRUE};
  131. #endif
  132.  
  133. #if OS2
  134. char    o_viomode[1] =        {TRUE};
  135. #endif
  136.  
  137. #ifndef NO_SHOWMATCH
  138. char    o_showmatch[1] =    {FALSE};
  139. #endif
  140.  
  141. #ifndef    NO_SHOWMODE
  142. char    o_smd[1] =        {FALSE};
  143. #endif
  144.  
  145. #ifndef NO_TAGSTACK
  146. char    o_tagstack[1] =        {TRUE};
  147. #endif
  148.  
  149. #ifndef NO_SAFER
  150. char    o_safer[1] =        {FALSE};
  151. #endif
  152.  
  153. #ifdef DEBUG
  154. char    o_slowmacro[1] =     {FALSE};
  155. #endif
  156.  
  157.  
  158.  
  159. /* The following describes the names & types of all options */
  160. #define BOOL    0
  161. #define    NUM    1
  162. #define    STR    2
  163. #define SET    0x01    /* this option has had its value altered */
  164. #define CANSET    0x02    /* this option can be set at any time */
  165. #define RCSET    0x06    /* this option can be set in a .exrc file only */
  166. #define NOSAVE    0x0a    /* this option should never be saved by mkexrc */
  167. #define MR    0x20    /* does this option affect the way text is displayed? */
  168. #define UNSAFE    0x40    /* is this option unsafe inside a ./.exrc file? */
  169. struct
  170. {
  171.     char    *name;    /* name of an option */
  172.     char    *nm;    /* short name of an option */
  173.     char    type;    /* type of an option */
  174.     char    flags;    /* boolean: has this option been set? */
  175.     char    *value;    /* value */
  176. }
  177.     opts[] =
  178. {
  179.     /* name            type    flags        value */
  180.     { "autoindent",    "ai",    BOOL,    CANSET,        o_autoindent    },
  181.     { "autoprint",    "ap",    BOOL,    CANSET,        o_autoprint    },
  182.     { "autotab",    "at",    BOOL,    CANSET,        o_autotab    },
  183.     { "autowrite",    "aw",    BOOL,    CANSET|UNSAFE,    o_autowrite    },
  184. #ifndef CRUNCH
  185.     { "beautify",    "bf",    BOOL,    CANSET,        o_beautify    },
  186. #endif
  187. #ifndef NO_ERRLIST
  188.     { "cc",        "cc",    STR,    CANSET|UNSAFE,    o_cc        },
  189. #endif
  190. #ifndef NO_CHARATTR
  191.     { "charattr",    "ca",    BOOL,    CANSET|MR,    o_charattr    },
  192. #endif
  193.     { "columns",    "co",    NUM,    SET|NOSAVE|MR,    o_columns    },
  194. #if MSDOS
  195.     { "controlz",    "z",    BOOL,    CANSET,        o_controlz    },
  196. #endif
  197. #ifndef NO_DIGRAPH
  198.     { "digraph",    "dig",    BOOL,    CANSET,        o_digraph    },
  199. #endif
  200.     { "directory",    "dir",    STR,    RCSET|UNSAFE,    o_directory    },
  201.     { "edcompatible","ed",    BOOL,    CANSET,        o_edcompatible    },
  202.     { "equalprg",    "ep",    STR,    CANSET|UNSAFE,    o_equalprg    },
  203.     { "errorbells",    "eb",    BOOL,    CANSET,        o_errorbells    },
  204. #ifndef CRUNCH
  205.     { "exrc",    "exrc",    BOOL,    CANSET,        o_exrc        },
  206. #endif
  207.     { "exrefresh",    "er",    BOOL,    CANSET,        o_exrefresh    },
  208.     { "flash",    "vbell",BOOL,    CANSET,        o_flash        },
  209. #ifndef NO_DIGRAPH
  210.     { "flipcase",    "fc",    STR,    CANSET,        o_flipcase    },
  211. #endif
  212. #ifndef NO_SENTENCE
  213.     { "hideformat",    "hf",    BOOL,    CANSET|MR,    o_hideformat    },
  214. #endif
  215.     { "ignorecase",    "ic",    BOOL,    CANSET,        o_ignorecase    },
  216. #ifndef NO_EXTENSIONS
  217.     { "inputmode",    "im",    BOOL,    CANSET,        o_inputmode    },
  218.     { "keepanon",    "ka",    BOOL,    CANSET,        o_keepanon    },
  219. #endif
  220.     { "keytime",    "kt",    NUM,    CANSET,        o_keytime    },
  221.     { "keywordprg",    "kp",    STR,    CANSET|UNSAFE,    o_keywordprg    },
  222.     { "lines",    "ls",    NUM,    SET|NOSAVE|MR,    o_lines        },
  223.     { "list",    "li",    BOOL,    CANSET|MR,    o_list        },
  224. #ifndef NO_MAGIC
  225.     { "magic",    "ma",    BOOL,    CANSET,        o_magic        },
  226. #endif
  227. #ifndef NO_ERRLIST
  228.     { "make",    "mk",    STR,    CANSET|UNSAFE,    o_make        },
  229. #endif
  230. #ifndef CRUNCH
  231.     { "mesg",    "me",    BOOL,    CANSET,        o_mesg        },
  232. #endif
  233. #ifndef NO_MODELINES
  234.     { "modelines",    "ml",    BOOL,    CANSET,        o_modelines    },
  235. #endif
  236. #ifndef CRUNCH
  237.     { "more",    "mo",    BOOL,    CANSET,        o_more        },
  238.     { "nearscroll",    "ns",    NUM,    CANSET,        o_nearscroll    },
  239.     { "newfile",    "new",    BOOL,    NOSAVE,        o_newfile    },
  240.     { "novice",    "nov",    BOOL,    CANSET,        o_novice    },
  241. #endif
  242.     { "number",    "nu",    BOOL,    CANSET|MR,    o_number    },
  243. #ifndef CRUNCH
  244.     { "optimize",    "opt",    BOOL,    CANSET,        o_optimize    },
  245. #endif
  246. #ifndef NO_SENTENCE
  247.     { "paragraphs",    "para",    STR,    CANSET,        o_paragraphs    },
  248. #endif
  249. #if MSDOS
  250.     { "pcbios",    "pc",    BOOL,    SET|NOSAVE,    o_pcbios    },
  251. #endif
  252. #ifndef CRUNCH
  253.     { "prompt",    "pr",    BOOL,    CANSET,        o_prompt    },
  254. #endif
  255.     { "readonly",    "ro",    BOOL,    CANSET,        o_readonly    },
  256.     { "remap",    "remap",BOOL,    CANSET,        o_remap        },
  257.     { "report",    "re",    NUM,    CANSET,        o_report    },
  258. #ifndef NO_EXTENSIONS
  259.     { "ruler",    "ru",    BOOL,    CANSET,        o_ruler        },
  260. #endif
  261. #ifndef NO_SAFER
  262.     { "safer",    "mostlyharmless",
  263.                 BOOL,    CANSET|UNSAFE,    o_safer        },
  264. #endif
  265.     { "scroll",    "sc",    NUM,    CANSET,        o_scroll    },
  266. #ifndef NO_SENTENCE
  267.     { "sections",    "sect",    STR,    CANSET,        o_sections    },
  268. #endif
  269.     { "shell",    "sh",    STR,    CANSET|UNSAFE,    o_shell        },
  270. #ifndef NO_SHOWMATCH
  271.     { "showmatch",    "sm",    BOOL,    CANSET,        o_showmatch    },
  272. #endif
  273. #ifndef    NO_SHOWMODE
  274.     { "showmode",    "smd",    BOOL,    CANSET,        o_smd        },
  275. #endif
  276.     { "shiftwidth",    "sw",    NUM,    CANSET,        o_shiftwidth    },
  277.     { "sidescroll",    "ss",    NUM,    CANSET,        o_sidescroll    },
  278. #ifdef DEBUG
  279.     { "slowmacro",    "slow",    BOOL,    CANSET,        o_slowmacro    },
  280. #endif
  281.     { "sync",    "sy",    BOOL,    CANSET,        o_sync        },
  282.     { "tabstop",    "ts",    NUM,    CANSET|MR,    o_tabstop    },
  283. #ifndef CRUNCH
  284.     { "taglength",    "tl",    NUM,    CANSET,        o_taglength    },
  285.     { "tags",    "tag",    STR,    CANSET,        o_tags        },
  286. #endif
  287. #ifndef NO_TAGSTACK
  288.     { "tagstack",    "tgs",    BOOL,    CANSET,        o_tagstack    },
  289. #endif
  290.     { "term",    "te",    STR,    SET,        o_term        },
  291. #ifndef CRUNCH
  292.     { "terse",    "tr",    BOOL,    CANSET,        o_terse        },
  293.     { "timeout",    "to",    BOOL,    CANSET,        o_keytime    },
  294. #endif
  295. #if OS2
  296.     { "viomode",    "vm",    BOOL,    CANSET|MR,    o_viomode    },
  297. #endif
  298.     { "warn",    "wa",    BOOL,    CANSET,        o_warn        },
  299. #ifndef CRUNCH
  300.     { "window",    "wi",    NUM,    CANSET|MR,    o_window    },
  301.     { "wrapmargin",    "wm",    NUM,    CANSET,        o_wrapmargin    },
  302. #endif
  303.     { "wrapscan",    "ws",    BOOL,    CANSET,        o_wrapscan    },
  304. #ifndef CRUNCH
  305.     { "writeany",    "wr",    BOOL,    CANSET,        o_writeany    },
  306. #endif
  307.     { NULL, NULL, 0, CANSET, NULL }
  308. };
  309. #define E_MAXOPTS    (sizeof(opts) / sizeof(opts[0]))
  310.  
  311.  
  312. /* This function initializes certain options from environment variables, etc. */
  313. void initopts()
  314. {
  315.     char    *val;
  316.     int    i;
  317. #if VMS
  318.     int    tty_ichan;
  319.     char    chbuf[12];
  320.     $DESCRIPTOR(inpdev,"TT");
  321.     int     err;
  322.     struct  terminfo {
  323.         unsigned class:8;
  324.         unsigned type:8;
  325.         unsigned pwidth:16;
  326.         unsigned tchar:22;
  327.         unsigned dummy:2;
  328.         unsigned plength:8;
  329.         unsigned xchar:32;
  330.     } tinfo;
  331.     struct iostab {
  332.         short int status;
  333.         short int terminator_offset;
  334.         short int terminator;
  335.         short int terminator_size;
  336.     } iostab;
  337. #endif /* VMS */
  338.  
  339.     /* set some stuff from environment variables */
  340. #if MSDOS || OS2
  341.     if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */
  342. #else
  343.     if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */
  344. #endif
  345.     {
  346.         strcpy(o_shell, val);
  347.     }
  348.  
  349.     strcpy(o_term, termtype);
  350. #if MSDOS
  351.     if (strcmp(termtype, "pcbios"))
  352.     {
  353.         o_pcbios[0] = FALSE;
  354.     }
  355.     else
  356.     {
  357.         o_pcbios[0] = TRUE;
  358.     }
  359. #endif
  360.  
  361. #if AMIGA || MSDOS || TOS || OS2
  362.     if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */
  363.     ||  (val = getenv("TEMP")))
  364.         strcpy(o_directory, val);
  365. #endif
  366.  
  367. #if !VMS
  368.  
  369. #ifndef CRUNCH
  370.     if ((val = getenv("LINES")) && atoi(val) > 4) /* yes, ASSIGNMENT! */
  371.     {
  372.         LINES = atoi(val);
  373.     }
  374.     if ((val = getenv("COLUMNS")) && atoi(val) > 30) /* yes, ASSIGNMENT! */
  375.     {
  376.         COLS = atoi(val);
  377.     }
  378. #endif
  379.  
  380. #else /* VMS */
  381.     if((err=sys$assign(&inpdev,&tty_ichan,0,0)) != SS$_NORMAL) {
  382.         fprintf(stderr,"KBIN assign failed. err=%x\n", err);
  383.         exit(err);
  384.     }
  385.     err=sys$qiow(1,tty_ichan,IO$_SENSEMODE,&iostab,NULL,0,
  386.         &tinfo,sizeof(tinfo),0,0,0,0);
  387.     LINES=tinfo.plength;
  388.     COLS=tinfo.pwidth;
  389. #endif /* VMS */
  390.  
  391.     *o_lines = LINES;
  392.     *o_columns = COLS;
  393.     *o_scroll = LINES / 2 - 1;
  394. #ifndef CRUNCH
  395.     if (o_window[0] == 0)
  396.     {
  397.         *o_nearscroll = o_window[2] = *o_lines;
  398.     }
  399. #endif
  400.  
  401.     /* disable the flash option if we don't know how to do a flash */
  402.     if (!has_VB)
  403.     {
  404.         for (i = 0; opts[i].value != o_flash; i++)
  405.         {
  406.         }
  407.         opts[i].flags &= ~CANSET;
  408.         *o_flash = FALSE;
  409.     }
  410.  
  411. #ifndef NO_DIGRAPH
  412. # ifdef CS_LATIN1
  413.     for (i = 0, val = o_flipcase; i < 32; i++)
  414.     {
  415.         /* leave out the multiply/divide symbols */
  416.         if (i == 23)
  417.             continue;
  418.  
  419.         /* add lower/uppercase pair */
  420.         *val++ = i + 0xe0;
  421.         *val++ = i + 0xc0;
  422.     }
  423.     *val = '\0';
  424. # endif /* CS_LATIN1 */
  425.  
  426.     /* initialize the ctype package */
  427.     _ct_init(o_flipcase);
  428. #else
  429.     _ct_init("");
  430. #endif /* not NO_DIGRAPH */
  431. }
  432.  
  433. /* This function lists the current values of all options */
  434. void dumpopts(all)
  435.     int    all;    /* boolean: dump all options, or just set ones? */
  436. {
  437. #ifndef NO_OPTCOLS
  438.     int    i, j, k;
  439.     char    nbuf[4];        /* used for converting numbers to ASCII */
  440.     int    widths[5];        /* width of each column, including gap */
  441.     int    ncols;            /* number of columns */
  442.     int    nrows;            /* number of options per column */
  443.     int    nset;            /* number of options to be output */
  444.     int    width;            /* width of a particular option */
  445.     int    todump[E_MAXOPTS];  /* indicies of options to be dumped */
  446.  
  447.     /* step 1: count the number of set options */
  448.     for (nset = i = 0; opts[i].name; i++)
  449.     {
  450.         if (all || (opts[i].flags & SET))
  451.         {
  452.             todump[nset++] = i;
  453.         }
  454.     }
  455.  
  456.     /* step two: try to use as many columns as possible */
  457.     for (ncols = (nset > 5 ? 5 : nset); ncols > 1; ncols--)
  458.     {
  459.         /* how many would go in this column? */
  460.         nrows = (nset + ncols - 1) / ncols;
  461.  
  462.         /* figure out the width of each column */
  463.         for (i = 0; i < ncols; i++)
  464.         {
  465.             widths[i] = 0;
  466.             for (j = 0, k = nrows * i; j < nrows && k < nset; j++, k++)
  467.             {
  468.                 /* figure out the width of a particular option */
  469.                 switch (opts[todump[k]].type)
  470.                 {
  471.                   case BOOL:
  472.                     if (!*opts[todump[k]].value)
  473.                         width = 2;
  474.                     else
  475.                         width = 0;
  476.                     break;
  477.  
  478.                   case STR:
  479.                     width = 3 + strlen(opts[todump[k]].value);
  480.                     if (width > MAXWIDTH)
  481.                         width = MAXWIDTH;
  482.                     break;
  483.  
  484.                   case NUM:
  485.                     width = 4;
  486.                     break;
  487.                 }
  488.                 width += strlen(opts[todump[k]].name);
  489.  
  490.                 /* if this is the widest so far, widen col */
  491.                 if (width > widths[i])
  492.                 {
  493.                     widths[i] = width;
  494.                 }
  495.             }
  496.  
  497.         }
  498.  
  499.         /* if the total width is narrow enough, then use it */
  500.         for (width = -2, i = 0; i < ncols; i++)
  501.         {
  502.             width += widths[i] + 2;
  503.         }
  504.         if (width < COLS - 1)
  505.         {
  506.             break;
  507.         }
  508.     }
  509.  
  510.     /* step 3: output the columns */
  511.     nrows = (nset + ncols - 1) / ncols;
  512.     for (i = 0; i < nrows; i++)
  513.     {
  514.         for (j = 0; j < ncols; j++)
  515.         {
  516.             /* if we hit the end of the options, quit */
  517.             k = i + j * nrows;
  518.             if (k >= nset)
  519.             {
  520.                 break;
  521.             }
  522.  
  523.             /* output this option's value */
  524.             width = 0;
  525.             switch (opts[todump[k]].type)
  526.             {
  527.               case BOOL:
  528.                 if (!*opts[todump[k]].value)
  529.                 {
  530.                     qaddch('n');
  531.                     qaddch('o');
  532.                     width = 2;
  533.                 }
  534.                 qaddstr(opts[todump[k]].name);
  535.                 width += strlen(opts[todump[k]].name);
  536.                 break;
  537.  
  538.               case NUM:
  539.                 sprintf(nbuf, "%-3d", UCHAR(*opts[todump[k]].value));
  540.                 qaddstr(opts[todump[k]].name);
  541.                 qaddch('=');
  542.                 qaddstr(nbuf);
  543.                 width = 4 + strlen(opts[todump[k]].name);
  544.                 break;
  545.  
  546.               case STR:
  547.                 qaddstr(opts[todump[k]].name);
  548.                 qaddch('=');
  549.                 qaddch('"');
  550.                 strcpy(tmpblk.c, opts[todump[k]].value);
  551.                 width = 3 + strlen(tmpblk.c);
  552.                 if (width > MAXWIDTH)
  553.                 {
  554.                     width = MAXWIDTH;
  555.                     strcpy(tmpblk.c + MAXWIDTH - 6, "...");
  556.                 }
  557.                 qaddstr(tmpblk.c);
  558.                 qaddch('"');
  559.                 width += strlen(opts[todump[k]].name);
  560.                 break;
  561.             }
  562.  
  563.             /* pad the field to the correct size */
  564.             if (k + nrows <= nset)
  565.             {
  566.                 while (width < widths[j] + 2)
  567.                 {
  568.                     qaddch(' ');
  569.                     width++;
  570.                 }
  571.             }
  572.         }
  573.         addch('\n');
  574.         exrefresh();
  575.     }
  576. #else
  577.     int    i;
  578.     int    col;
  579.     char    nbuf[4];
  580.  
  581.     for (i = col = 0; opts[i].name; i++)
  582.     {
  583.         /* if not set and not all, ignore this option */
  584.         if (!all && !(opts[i].flags & SET))
  585.         {
  586.             continue;
  587.         }
  588.  
  589.         /* align this option in one of the columns */
  590.         if (col > 52)
  591.         {
  592.             addch('\n');
  593.             col = 0;
  594.         }
  595.         else if (col > 26)
  596.         {
  597.             while (col < 52)
  598.             {
  599.                 qaddch(' ');
  600.                 col++;
  601.             }
  602.         }
  603.         else if (col > 0)
  604.         {
  605.             while (col < 26)
  606.             {
  607.                 qaddch(' ');
  608.                 col++;
  609.             }
  610.         }
  611.  
  612.         switch (opts[i].type)
  613.         {
  614.           case BOOL:
  615.             if (!*opts[i].value)
  616.             {
  617.                 qaddch('n');
  618.                 qaddch('o');
  619.                 col += 2;
  620.             }
  621.             qaddstr(opts[i].name);
  622.             col += strlen(opts[i].name);
  623.             break;
  624.  
  625.           case NUM:
  626.             sprintf(nbuf, "%-3d", UCHAR(*opts[i].value));
  627.             qaddstr(opts[i].name);
  628.             qaddch('=');
  629.             qaddstr(nbuf);
  630.             col += 4 + strlen(opts[i].name);
  631.             break;
  632.  
  633.           case STR:
  634.             qaddstr(opts[i].name);
  635.             qaddch('=');
  636.             qaddch('"');
  637.             qaddstr(opts[i].value);
  638.             qaddch('"');
  639.             col += 3 + strlen(opts[i].name) + strlen(opts[i].value);
  640.             break;
  641.         }
  642.         exrefresh();
  643.     }
  644.     if (col > 0)
  645.     {
  646.         addch('\n');
  647.         exrefresh();
  648.     }
  649. #endif
  650. }
  651.  
  652. #ifndef NO_MKEXRC
  653. /* This function saves the current configuration of options to a file */
  654. void saveopts(fd)
  655.     int    fd;    /* file descriptor to write to */
  656. {
  657.     int    i;
  658.     char    buf[256], *pos;
  659.  
  660.     /* write each set options */
  661.     for (i = 0; opts[i].name; i++)
  662.     {
  663.         /* if unset or unsettable, ignore this option */
  664.         if ((opts[i].flags & (SET|CANSET|NOSAVE)) != (SET|CANSET))
  665.         {
  666.             continue;
  667.         }
  668.  
  669.         strcpy(buf, "set ");
  670.         pos = &buf[4];
  671.         switch (opts[i].type)
  672.         {
  673.           case BOOL:
  674.             if (!*opts[i].value)
  675.             {
  676.                 *pos++='n';
  677.                 *pos++='o';
  678.             }
  679.             strcpy(pos, opts[i].name);
  680.             strcat(pos, "\n");
  681.             break;
  682.  
  683.           case NUM:
  684.             sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff);
  685.             break;
  686.  
  687.           case STR:
  688.             sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value);
  689.             break;
  690.         }
  691.         twrite(fd, buf, (unsigned)strlen(buf));
  692.     }
  693. }
  694. #endif
  695.  
  696.  
  697. /* This function changes the values of one or more options. */
  698. void setopts(assignments)
  699.     char    *assignments;    /* a string containing option assignments */
  700. {
  701.     char    *name;        /* name of variable in assignments */
  702.     char    *value;        /* value of the variable */
  703.     char    *scan;        /* used for moving through strings */
  704.     char    *build;        /* used for copying chars from "scan" */
  705.     char    *prefix;    /* pointer to "neg" or "no" at front of a boolean */
  706.     int    quote;        /* boolean: inside '"' quotes? */
  707.     int    i, j;
  708.  
  709. #ifndef CRUNCH
  710.     /* reset the upper limit of "window" option to lines-1 */
  711.     o_window[2] = *o_lines - 1;
  712. #endif
  713.  
  714.     /* for each assignment... */
  715.     for (name = assignments; *name; )
  716.     {
  717.         /* skip whitespace */
  718.         if (*name == ' ' || *name == '\t')
  719.         {
  720.             name++;
  721.             continue;
  722.         }
  723.  
  724.         /* after the name, find the value (if any) */
  725.         for (scan = name; isalnum(*scan); scan++)
  726.         {
  727.         }
  728.         if (*scan == '=')
  729.         {
  730.             *scan++ = '\0';
  731.             value = build = scan;
  732.             for (quote = FALSE; *scan && (quote || !isspace(*scan)); scan++)
  733.             {
  734.                 if (*scan == '"')
  735.                 {
  736.                     quote = !quote;
  737.                 }
  738.                 else if (*scan == '\\' && scan[1] && !isalnum(scan[1]))
  739.                 {
  740.                     *build++ = *++scan;
  741.                 }
  742.                 else
  743.                 {
  744.                     *build++ = *scan;
  745.                 }
  746.             }
  747.             if (*scan)
  748.                 scan++;
  749.             *build = '\0';
  750.         }
  751.         else /* no "=" so it is probably boolean... */
  752.         {
  753.             if (*scan)
  754.             {
  755.                 *scan++ = '\0';
  756.             }
  757.             value = NULL;
  758.             prefix = name;
  759. #ifndef CRUNCH
  760.             if (!strcmp(name, "novice"))
  761.                 /* don't check for a "no" prefix */;
  762.             else
  763. #endif
  764.             if (prefix[0] == 'n' && prefix[1] == 'o')
  765.                 name += 2;
  766.             else if (prefix[0] == 'n' && prefix[1] == 'e' && prefix[2] == 'g')
  767.                 name += 3;
  768.         }
  769.  
  770.         /* find the variable */
  771.         for (i = 0;
  772.              opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name);
  773.              i++)
  774.         {
  775.         }
  776.  
  777.         /* change the variable */
  778.         if (!opts[i].name)
  779.         {
  780.             /* only complain about unknown options if we're editing
  781.              * a file;  i.e., if we're not executing the .exrc now.
  782.              */
  783.             if (tmpfd >= 0)
  784.                 msg("invalid option name \"%s\"", name);
  785.         }
  786. #ifndef NO_SAFER
  787.         else if ((opts[i].flags & UNSAFE) == UNSAFE && *o_safer)
  788.         {
  789.             msg("option \"%s\" is unsafe", name);
  790.         }
  791. #endif
  792.         else if ((opts[i].flags & CANSET) != CANSET)
  793.         {
  794.             msg("option \"%s\" can't be altered", name);
  795.         }
  796.         else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L)
  797.         {
  798.             msg("option \"%s\" can only be set in a %s file", name, EXRC);
  799.         }
  800.         else if (value)
  801.         {
  802.             switch (opts[i].type)
  803.             {
  804.               case BOOL:
  805.                 msg("option \"[no]%s\" is boolean", name);
  806.                 break;
  807.  
  808.               case NUM:
  809.                 j = atoi(value);
  810.                 if (j == 0 && *value != '0')
  811.                 {
  812.                     msg("option \"%s\" must have a numeric value", name);
  813.                 }
  814.                 else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff))
  815.                 {
  816.                     msg("option \"%s\" must have a value between %d and %d",
  817.                         name, opts[i].value[1], opts[i].value[2] & 0xff);
  818.                 }
  819.                 else
  820.                 {
  821.                     *opts[i].value = atoi(value);
  822.                     opts[i].flags |= SET;
  823.                 }
  824.                 break;
  825.  
  826.               case STR:
  827.                 strcpy(opts[i].value, value);
  828.                 opts[i].flags |= SET;
  829.                 break;
  830.             }
  831.             if (opts[i].flags & MR)
  832.             {
  833.                 redraw(MARK_UNSET, FALSE);
  834.             }
  835.         }
  836.         else /* valid option, no value */
  837.         {
  838.             if (opts[i].type == BOOL)
  839.             {
  840.                 if (prefix == name)
  841.                     *opts[i].value = TRUE;
  842.                 else if (prefix[1] == 'o')
  843.                     *opts[i].value = FALSE;
  844.                 else
  845.                     *opts[i].value = !*opts[i].value;
  846.  
  847.                 opts[i].flags |= SET;
  848.                 if (opts[i].flags & MR)
  849.                 {
  850.                     redraw(MARK_UNSET, FALSE);
  851.                 }
  852.             }
  853.             else
  854.             {
  855.                 msg("option \"%s\" must be given a value", name);
  856.             }
  857.         }
  858.  
  859.         /* move on to the next option */
  860.         name = scan;
  861.     }
  862.  
  863.     /* special processing ... */
  864.  
  865. #ifndef CRUNCH
  866.     /* if "novice" is set, then ":set report=1 showmode nomagic" */
  867.     if (*o_novice)
  868.     {
  869.         *o_report = 1;
  870. # ifndef NO_SHOWMODE
  871.         *o_smd = TRUE;
  872. # endif
  873. # ifndef NO_MAGIC
  874.         *o_magic = FALSE;
  875. # endif
  876.     }
  877. #endif
  878.  
  879.     /* if "readonly" then set the READONLY flag for this file */
  880.     if (*o_readonly)
  881.     {
  882.         setflag(file, READONLY);
  883.     }
  884.  
  885. #ifndef NO_DIGRAPH
  886.     /* re-initialize the ctype package */
  887.     _ct_init(o_flipcase);
  888. #endif /* not NO_DIGRAPH */
  889.  
  890.     /* copy o_lines and o_columns into LINES and COLS */
  891.     LINES = (*o_lines & 255);
  892.     COLS = (*o_columns & 255);
  893. }
  894.  
  895.  
  896.  
  897.  
  898. #ifndef NO_IF
  899.  
  900. static char *parseif(ptr, buf)
  901.     char    *ptr;    /* pointer into "extra" of the start of the value */
  902.     char    *buf;    /* where to store a copy of the value string */
  903. {
  904.     char    tmp[30];
  905.     char    *build;
  906.     int    i;
  907.  
  908.     /* skip any leading whitespace */
  909.     while (*ptr && isspace(*ptr))
  910.     {
  911.         ptr++;
  912.     }
  913.  
  914.     /* parsing depends on first character */
  915.     switch (*ptr)
  916.     {
  917.       case ':':
  918.         ptr++;
  919.         for (build = tmp; *ptr && *ptr != ':';)
  920.         {
  921.             *build++ = *ptr++;
  922.         }
  923.         if (*ptr) ptr++;
  924.         *build = '\0';
  925.         if (!tgetstr(tmp, &buf))
  926.         {
  927.             i = tgetnum(tmp);
  928.             if (i < 0)
  929.                 strcpy(buf, tgetflag(tmp) ? "True" : "False");
  930.             else
  931.                 sprintf(buf, "%d", i);
  932.         }
  933.         break;
  934.  
  935.       case '$':
  936.         ptr++;
  937.         for (build = tmp; *ptr && isalnum(*ptr);)
  938.         {
  939.             *build++ = *ptr++;
  940.         }
  941.         *build = '\0';
  942.         build = getenv(tmp);
  943.         strcpy(buf, build ? build : "False");
  944.         break;
  945.  
  946.       case '"':
  947.         ptr++;
  948.         while (*ptr && *ptr != '"')
  949.         {
  950.             *buf++ = *ptr++;
  951.         }
  952.         *buf = '\0';
  953.         break;
  954.  
  955.       case '0':
  956.       case '1':
  957.       case '2':
  958.       case '3':
  959.       case '4':
  960.       case '5':
  961.       case '6':
  962.       case '7':
  963.       case '8':
  964.       case '9':
  965.         while (*ptr && isdigit(*ptr))
  966.         {
  967.             *buf++ = *ptr++;
  968.         }
  969.         *buf = '\0';
  970.         break;
  971.  
  972.       case '*':
  973.         for (build = ptr + 1; *build;)
  974.         {
  975.             *buf++ = *build++;
  976.         }
  977.         *buf = '\0';
  978.         break;
  979.  
  980.       default:
  981.         for (build = tmp; *ptr && isalnum(*ptr);)
  982.         {
  983.             *build++ = *ptr++;
  984.         }
  985.         *build = '\0';
  986.         for (i = 0; opts[i].name && strcmp(opts[i].name, tmp) && strcmp(opts[i].nm, tmp); i++)
  987.         {
  988.         }
  989.         if (!opts[i].name && !strncmp(tmp, "no", 2))
  990.         {
  991.             for (i = 0; opts[i].name && (opts[i].type != BOOL || strcmp(opts[i].name, tmp+2) && strcmp(opts[i].nm, tmp+2)); i++)
  992.             {
  993.             }
  994.         }
  995.         if (!opts[i].name)
  996.         {
  997.             msg("invalid option name \"%s\"", tmp);
  998.             beep();
  999.             return (char *)0;
  1000.         }
  1001.         switch (opts[i].type)
  1002.         {
  1003.           case BOOL:
  1004.             if (!strncmp(tmp, "no", 2) && strcmp(tmp, "novice"))
  1005.             {
  1006.                 strcpy(buf, *opts[i].value ? "False" : "True");
  1007.             }
  1008.             else
  1009.             {
  1010.                 strcpy(buf, *opts[i].value ? "True" : "False");
  1011.             }
  1012.             break;
  1013.  
  1014.           case NUM:
  1015.             sprintf(buf, "%d", *opts[i].value & 0xff);
  1016.             break;
  1017.  
  1018.           case STR:
  1019.             strcpy(buf, opts[i].value);
  1020.             break;
  1021.         }
  1022.     }
  1023.  
  1024.     /* skip any following whitespace */
  1025.     while (*ptr && isspace(*ptr))
  1026.     {
  1027.         ptr++;
  1028.     }
  1029.     return ptr;
  1030. }
  1031.  
  1032. static int ifflag;
  1033.  
  1034. /*ARGSUSED*/
  1035. void cmd_if(frommark, tomark, cmd, bang, extra)
  1036.     MARK    frommark;
  1037.     MARK    tomark;
  1038.     CMD    cmd;
  1039.     int    bang;
  1040.     char    *extra;
  1041. {
  1042.     char    *op;
  1043.     int    val;
  1044.  
  1045.     /* parse the LHS of the comparison */
  1046.     op = parseif(extra, tmpblk.c);
  1047.     if (!op) return;
  1048.  
  1049.     /* parse the RHS, if any */
  1050.     if (*op && *op != '*')
  1051.     {
  1052.         if (op[1] == '=')
  1053.             extra = op + 2;
  1054.         else
  1055.             extra = op + 1;
  1056.         if (!parseif(extra, tmpblk.c + strlen(tmpblk.c) + 1))
  1057.             return;
  1058.         extra = tmpblk.c + strlen(tmpblk.c) + 1;
  1059.     }
  1060.  
  1061.     /* parse the operator.  If none, assume boolean test */
  1062.     switch (*op)
  1063.     {
  1064.       case '\0':
  1065.         val = strcmp(tmpblk.c, "False");
  1066.         break;
  1067.  
  1068.       case '<':
  1069.         if (op[1] == '=')
  1070.             val = (atoi(tmpblk.c) <= atoi(extra));
  1071.         else
  1072.             val = (atoi(tmpblk.c) < atoi(extra));
  1073.         break;
  1074.  
  1075.       case '>':
  1076.         if (op[1] == '=')
  1077.             val = (atoi(tmpblk.c) >= atoi(extra));
  1078.         else
  1079.             val = (atoi(tmpblk.c) > atoi(extra));
  1080.         break;
  1081.  
  1082.       case '=':
  1083.         val = !strcmp(tmpblk.c, extra);
  1084.         break;
  1085.  
  1086.       case '!':
  1087.         val = strcmp(tmpblk.c, extra);
  1088.         break;
  1089.  
  1090.       case '*':
  1091.         val = (strlen(origname) >= strlen(tmpblk.c)
  1092.             && !strcmp(origname + strlen(origname) - strlen(tmpblk.c), tmpblk.c));
  1093.         break;
  1094.     }
  1095.  
  1096.     /* merge these results into value */
  1097.     switch (cmd)
  1098.     {
  1099.       case CMD_IF:    ifflag = val;    break;
  1100.       case CMD_OR:    ifflag |= val;    break;
  1101.       case CMD_AND:    ifflag &= val;    break;
  1102.     }
  1103. }
  1104.  
  1105.  
  1106.  
  1107. void cmd_then(frommark, tomark, cmd, bang, extra)
  1108.     MARK    frommark;
  1109.     MARK    tomark;
  1110.     CMD    cmd;
  1111.     int    bang;
  1112.     char    *extra;
  1113. {
  1114.     if (cmd == CMD_THEN && ifflag || cmd == CMD_ELSE && !ifflag)
  1115.     {
  1116.         doexcmd(extra, '\\');
  1117.     }
  1118. }
  1119.  
  1120. #endif /* ndef NO_IF */
  1121.