home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / modes.c < prev    next >
C/C++ Source or Header  |  1998-07-17  |  59KB  |  2,618 lines

  1. /*
  2.  *    modes.c
  3.  *
  4.  * Maintain and list the editor modes and value sets.
  5.  *
  6.  * Original code probably by Dan Lawrence or Dave Conroy for MicroEMACS.
  7.  * Major extensions for vile by Paul Fox, 1991
  8.  * Majormode extensions for vile by T.E.Dickey, 1997
  9.  *
  10.  * $Header: /usr/build/vile/vile/RCS/modes.c,v 1.119 1998/07/17 10:25:48 tom Exp $
  11.  *
  12.  */
  13.  
  14. #include    "estruct.h"
  15. #include    "edef.h"
  16. #include    "chgdfunc.h"
  17.  
  18. #define    NonNull(s)    ((s == 0) ? "" : s)
  19. #define    ONE_COL    (80/3)
  20.  
  21. #define isLocalVal(valptr)          ((valptr)->vp == &((valptr)->v))
  22. #define makeLocalVal(valptr)        ((valptr)->vp = &((valptr)->v))
  23.  
  24. /* FIXME */
  25. #define OPT_COLOR_CHOICES    OPT_COLOR
  26. #define OPT_BOOL_CHOICES    1
  27. #define OPT_POPUP_CHOICES    OPT_POPUPCHOICE
  28. #define OPT_BACKUP_CHOICES    OPT_FILEBACK
  29. #define OPT_HILITE_CHOICES    OPT_HILITEMATCH
  30.  
  31. #include "nefsms.h"
  32.  
  33. /*--------------------------------------------------------------------------*/
  34.  
  35. #if OPT_UPBUFF
  36. static    void    relist_settings (void);
  37. #else
  38. #define relist_settings() /* nothing */
  39. #endif
  40.  
  41. #if OPT_ENUM_MODES
  42. static    const char * choice_to_name (const FSM_CHOICES *choices, int code);
  43. static    const FSM_CHOICES * name_to_choices (const struct VALNAMES *names);
  44. #endif
  45.  
  46. /*--------------------------------------------------------------------------*/
  47.  
  48. #if OPT_EVAL || OPT_MAJORMODE
  49. static    const char **my_varmodes;    /* list for modename-completion */
  50. #endif
  51.  
  52. #if OPT_MAJORMODE
  53. typedef struct {
  54.     char *name;        /* copy of MAJORMODE.name */
  55.     MAJORMODE *data;    /* pointer to actual data */
  56.     int init;        /* predefined during initialization */
  57.     int flag;        /* true when majormode is active/usable */
  58.     struct VALNAMES qual[MAX_M_VALUES+1]; /* qualifier names */
  59.     struct VALNAMES used[MAX_B_VALUES+1]; /* submode names */
  60. } MAJORMODE_LIST;
  61.  
  62. static MAJORMODE_LIST *my_majormodes;
  63. static struct VALNAMES *major_valnames;
  64. static struct VAL *major_g_vals;    /* on/off values of major modes */
  65. static struct VAL *major_l_vals;    /* dummy, for convenience */
  66.  
  67. static const char **my_mode_list;    /* copy of 'all_modes[]' */
  68. #define MODE_CLASSES 5
  69. #define is_bool_type(type) ((type) == VALTYPE_BOOL || (type) == VALTYPE_MAJOR)
  70.  
  71. static MAJORMODE * lookup_mm_data(const char *name);
  72. static MAJORMODE_LIST * lookup_mm_list(const char *name);
  73. static char * majorname(char *dst, const char *majr, int flag);
  74. static const char *ModeName(const char *name);
  75. static int attach_mmode(BUFFER *bp, const char *name);
  76. static int detach_mmode(BUFFER *bp, const char *name);
  77. static int enable_mmode(const char *name, int flag);
  78. static void init_my_mode_list(void);
  79.  
  80. #if OPT_UPBUFF
  81. static void relist_majormodes(void);
  82. #endif
  83.  
  84. #else
  85.  
  86. #define MODE_CLASSES 3
  87. #define ModeName(s) s
  88. #define init_my_mode_list() /* nothing */
  89. #define is_bool_type(type) ((type) == VALTYPE_BOOL)
  90. #define my_mode_list all_modes
  91. #define relist_majormodes() /* nothing */
  92.  
  93. #endif /* OPT_MAJORMODE */
  94.  
  95. /*--------------------------------------------------------------------------*/
  96.  
  97. static void
  98. set_winflags(int glob_vals, USHORT flags)
  99. {
  100.     if (glob_vals) {
  101.         register WINDOW *wp;
  102.         for_each_visible_window(wp) {
  103.             if ((wp->w_bufp == NULL)
  104.              || !b_is_scratch(wp->w_bufp)
  105.              || !(flags & WFMODE))
  106.                 wp->w_flag |= flags;
  107.         }
  108.     } else {
  109.         curwp->w_flag |= flags;
  110.     }
  111. }
  112.  
  113. static int
  114. same_val(const struct VALNAMES *names, struct VAL *tst, struct VAL *ref)
  115. {
  116.     if (ref == 0)    /* can't test, not really true */
  117.         return -TRUE;
  118.  
  119.     switch (names->type) {
  120. #if OPT_MAJORMODE
  121.     case VALTYPE_MAJOR:
  122.         /*FALLTHRU*/
  123. #endif
  124.     case VALTYPE_BOOL:
  125.     case VALTYPE_ENUM:
  126.     case VALTYPE_INT:
  127.         return    (tst->vp->i == ref->vp->i);
  128.     case VALTYPE_STRING:
  129.         return    (tst->vp->p != 0)
  130.           &&    (ref->vp->p != 0)
  131.           &&    !strcmp(tst->vp->p, ref->vp->p);
  132.     case VALTYPE_REGEX:
  133.         return    (tst->vp->r->pat != 0)
  134.           &&    (ref->vp->r->pat != 0)
  135.           &&    !strcmp(tst->vp->r->pat, ref->vp->r->pat);
  136.     default:
  137.         mlforce("BUG: bad type %s %d", ModeName(names->name), names->type);
  138.     }
  139.  
  140.     return FALSE;
  141. }
  142.  
  143. /*
  144.  * Returns the value if it is a string, null otherwise.
  145.  */
  146. static const char *
  147. string_val(const struct VALNAMES *names, struct VAL *values)
  148. {
  149.     const char *s = 0;
  150.  
  151.     switch (names->type) {
  152. #if    OPT_ENUM_MODES        /* will show the enum name too */
  153.     case VALTYPE_ENUM:
  154.         s = choice_to_name(name_to_choices(names), values->vp->i);
  155.         break;
  156. #endif
  157.     case VALTYPE_STRING:
  158.         s = values->vp->p;
  159.         break;
  160.     case VALTYPE_REGEX:
  161.         if (values->vp->r)
  162.             s = values->vp->r->pat;
  163.         break;
  164.     }
  165.  
  166.     return (s != 0 && *s == EOS) ? 0 : s;
  167. }
  168.  
  169. /*
  170.  * Returns the formatted length of a string value.
  171.  */
  172. static int
  173. size_val(const struct VALNAMES *names, struct VAL *values)
  174. {
  175.     return strlen(ModeName(names->name))
  176.         + 3
  177.         + strlen(NonNull(string_val(names, values)));
  178. }
  179.  
  180. /*
  181.  * Returns a mode-value formatted as a string
  182.  */
  183. char *
  184. string_mode_val(VALARGS *args)
  185. {
  186.     register const struct VALNAMES *names = args->names;
  187.     register struct VAL     *values = args->local;
  188.     switch(names->type) {
  189. #if OPT_MAJORMODE
  190.     case VALTYPE_MAJOR:
  191. #endif
  192.     case VALTYPE_BOOL:
  193.         return values->vp->i ? truem : falsem;
  194.     case VALTYPE_ENUM:
  195. #if OPT_ENUM_MODES
  196.         {
  197.         static    char    temp[20];    /* FIXME: const workaround */
  198.         (void)strcpy(temp,
  199.             choice_to_name(name_to_choices(names), values->vp->i));
  200.         return temp;
  201.         }
  202. #endif                /* else, fall-thru to use int-code */
  203.     case VALTYPE_INT:
  204.         return l_itoa(values->vp->i);
  205.     case VALTYPE_STRING:
  206.         return NonNull(values->vp->p);
  207.     case VALTYPE_REGEX:
  208.         if (values->vp->r == 0)
  209.             break;
  210.         return NonNull(values->vp->r->pat);
  211.     }
  212.     return errorm;
  213. }
  214.  
  215. /* listvalueset:  print each value in the array according to type, along with
  216.  * its name, until a NULL name is encountered.  If not local, only print if the value in the
  217.  * two arrays differs, or the second array is nil.  If local, print only the
  218.  * values in the first array that are local.
  219.  */
  220. static int
  221. listvalueset(
  222. const char *which,
  223. int nflag,
  224. int local,
  225. const struct VALNAMES *names,
  226. struct VAL *values,
  227. struct VAL *globvalues)
  228. {
  229.     int    show[MAX_G_VALUES+MAX_B_VALUES+MAX_W_VALUES];
  230.     int    any    = 0,
  231.         passes    = 1,
  232.         ncols    = term.t_ncol / ONE_COL,
  233.         padded,
  234.         perline,
  235.         percol,
  236.         total;
  237.     register int j, pass;
  238.  
  239.     if (ncols > MAXCOLS)
  240.         ncols = MAXCOLS;
  241.  
  242.     /*
  243.      * First, make a list of values we want to show.
  244.      * Store:
  245.      *    0 - don't show
  246.      *    1 - show in first pass
  247.      *    2 - show in second pass (too long)
  248.      */
  249.     for (j = 0; names[j].name != 0; j++) {
  250.         int ok = FALSE;
  251.         show[j] = 0;
  252.         if (local) {
  253.             ok = is_local_val(values,j);
  254.         } else {
  255.             ok = (same_val(names+j, values+j, globvalues ? globvalues+j : 0) != TRUE);
  256.         }
  257.         if (ok) {
  258.             switch (names[j].type) {
  259.             case VALTYPE_STRING:
  260.             case VALTYPE_REGEX:
  261.                 if (string_val(names+j, values+j) == 0) {
  262.                     ok = FALSE;
  263.                     break;
  264.                 }
  265.                 if (size_val(names+j, values+j) > ONE_COL) {
  266.                     show[j] += 1;
  267.                     passes = 2;
  268.                 }
  269.                 /* fall-thru */
  270.             default:
  271.                 show[j] += 1;
  272.             }
  273.         }
  274.         if (ok && !any++) {
  275.             if (nflag)
  276.                 bputc('\n');
  277.             bprintf("%s:\n", which);
  278.         }
  279.     }
  280.     total = j;
  281.  
  282.     if (any) {
  283.         if (!passes)
  284.             passes = 1;
  285.     } else
  286.         return nflag;
  287.  
  288.     /*
  289.      * Now, go back and display the values
  290.      */
  291.     for (pass = 1; pass <= passes; pass++) {
  292.         register int    line, col, k;
  293.         int    offsets[MAXCOLS+1];
  294.  
  295.         offsets[0] = 0;
  296.         if (pass == 1) {
  297.             for (j = percol = 0; j < total; j++) {
  298.                 if (show[j] == pass)
  299.                     percol++;
  300.             }
  301.             for (j = 1; j < ncols; j++) {
  302.                 offsets[j]
  303.                     = (percol + ncols - j) / ncols
  304.                     + offsets[j-1];
  305.             }
  306.             perline = ncols;
  307.         } else {    /* these are too wide for ONE_COL */
  308.             offsets[1] = total;
  309.             perline = 1;
  310.         }
  311.         offsets[ncols] = total;
  312.  
  313.         line = 0;
  314.         col  = 0;
  315.         for_ever {
  316.             k = line + offsets[col];
  317.             for (j = 0; j < total; j++) {
  318.                 if (show[j] == pass) {
  319.                     if (k-- <= 0)
  320.                         break;
  321.                 }
  322.             }
  323.             if (k >= 0)    /* no more cells to display */
  324.                 break;
  325.  
  326.             if (col == 0)
  327.                 bputc(' ');
  328.             padded = (col+1) < perline ? ONE_COL : 1;
  329.             if (is_bool_type(names[j].type)) {
  330.                 bprintf("%s%s%*P",
  331.                     values[j].vp->i ? "  " : "no",
  332.                     ModeName(names[j].name),
  333.                     padded, ' ');
  334.             } else {
  335.                 VALARGS args;    /* patch */
  336.                 args.names  = names+j;
  337.                 args.local  = values+j;
  338.                 args.global = 0;
  339.                 bprintf("  %s=%s%*P",
  340.                     ModeName(names[j].name),
  341.                     string_mode_val(&args),
  342.                     padded, ' ');
  343.             }
  344.             if (++col >= perline) {
  345.                 col = 0;
  346.                 bputc('\n');
  347.                 if (++line >= offsets[1])
  348.                     break;
  349.             } else if (line+offsets[col] >= offsets[col+1])
  350.                 break;
  351.         }
  352.         if ((col != 0) || (pass != passes)) {
  353.             if (pass != passes)
  354.                 bputc('\n');
  355.             bputc('\n');
  356.         }
  357.     }
  358.     return TRUE;
  359. }
  360.  
  361. #ifdef lint
  362. static    /*ARGSUSED*/ WINDOW *ptr2WINDOW(void *p) { return 0; }
  363. #else
  364. #define    ptr2WINDOW(p)    (WINDOW *)p
  365. #endif
  366.  
  367. /* list the current modes into the current buffer */
  368. /* ARGSUSED */
  369. static
  370. void
  371. makemodelist(int local, void *ptr)
  372. {
  373.     static
  374.     const    char    gg[] = "Universal",
  375.             bb[] = "Buffer",
  376.             ww[] = "Window";
  377.     int    nflag, nflg2;
  378.  
  379.     register WINDOW *localwp = ptr2WINDOW(ptr);  /* alignment okay */
  380.     register BUFFER *localbp = localwp->w_bufp;
  381.     struct VAL    *local_b_vals = localbp->b_values.bv;
  382.     struct VAL    *local_w_vals = localwp->w_values.wv;
  383.     struct VAL    *globl_b_vals = global_b_values.bv;
  384.  
  385. #if OPT_UPBUFF
  386.     if (relisting_b_vals != 0)
  387.         local_b_vals = relisting_b_vals;
  388.     if (relisting_w_vals != 0)
  389.         local_w_vals = relisting_w_vals;
  390. #endif
  391.  
  392. #if OPT_MAJORMODE
  393.     if (local && (localbp->majr != 0)) {
  394.         bprintf("--- \"%s\" settings, if different than \"%s\" majormode %*P\n",
  395.             localbp->b_bname,
  396.             localbp->majr->name,
  397.             term.t_ncol-1, '-');
  398.         globl_b_vals = localbp->majr->mb.bv;
  399.     } else
  400. #endif
  401.     bprintf("--- \"%s\" settings, if different than globals %*P\n",
  402.         localbp->b_bname, term.t_ncol-1, '-');
  403.  
  404.     nflag = listvalueset(bb, FALSE, FALSE, b_valnames, local_b_vals, globl_b_vals);
  405.     nflg2 = listvalueset(ww, nflag, FALSE, w_valnames, local_w_vals, global_w_values.wv);
  406.     if (!(nflag || nflg2))
  407.          bputc('\n');
  408.     bputc('\n');
  409.  
  410.     bprintf("--- %s settings %*P\n",
  411.         local ? "Local" : "Global", term.t_ncol-1, '-');
  412.  
  413. #if OPT_MAJORMODE
  414.     if (!local) {
  415.         int n;
  416.         for (n = 0; major_valnames[n].name != 0; n++) {
  417.             make_local_val(major_g_vals, n);
  418.             major_g_vals[n].vp->i = my_majormodes[n].flag;
  419.         }
  420.         nflag = listvalueset("Majormodes", nflag, local, major_valnames, major_g_vals, (struct VAL *)0);
  421.     }
  422. #endif
  423.     if (local) {
  424.         nflag = listvalueset(bb, nflag, local, b_valnames, local_b_vals, (struct VAL *)0);
  425.         (void)  listvalueset(ww, nflag, local, w_valnames, local_w_vals, (struct VAL *)0);
  426.     } else {
  427.         nflag = listvalueset(gg, nflag, local, g_valnames, global_g_values.gv, (struct VAL *)0);
  428.         nflag = listvalueset(bb, nflag, local, b_valnames, globl_b_vals, (struct VAL *)0);
  429.         (void)  listvalueset(ww, nflag, local, w_valnames, global_w_values.wv, (struct VAL *)0);
  430.     }
  431. }
  432.  
  433. /*
  434.  * Set tab size
  435.  */
  436. int
  437. settab(int f, int n)
  438. {
  439.     register WINDOW *wp;
  440. #if OPT_MAJORMODE
  441.     int val = VAL_TAB;
  442.     const char *whichtabs = "T";
  443. #else
  444.     int val;
  445.     const char *whichtabs;
  446.     if (is_c_mode(curbp)) {
  447.         val = VAL_C_TAB;
  448.         whichtabs = "C-t";
  449.     } else {
  450.         val = VAL_TAB;
  451.         whichtabs = "T";
  452.     }
  453. #endif
  454.     if (f && n >= 1) {
  455.         make_local_b_val(curbp,val);
  456.         set_b_val(curbp,val,n);
  457.         curtabval = n;
  458.         for_each_visible_window(wp)
  459.             if (wp->w_bufp == curbp) wp->w_flag |= WFHARD;
  460.     } else if (f) {
  461.         mlwarn("[Illegal tabstop value]");
  462.         return FALSE;
  463.     }
  464.     if (!global_b_val(MDTERSE) || !f)
  465.         mlwrite("[%sabs are %d columns apart, using %s value.]", whichtabs,
  466.             curtabval,
  467.             is_local_b_val(curbp,val) ? "local" : "global" );
  468.     return TRUE;
  469. }
  470.  
  471. /*
  472.  * Set fill column to n.
  473.  */
  474. int
  475. setfillcol(int f, int n)
  476. {
  477.     if (f && n >= 1) {
  478.         make_local_b_val(curbp,VAL_FILL);
  479.         set_b_val(curbp,VAL_FILL,n);
  480.     } else if (f) {
  481.         mlwarn("[Illegal fill-column value]");
  482.         return FALSE;
  483.     }
  484.     if (!global_b_val(MDTERSE) || !f)
  485.         mlwrite("[Fill column is %d, and is %s]",
  486.             b_val(curbp,VAL_FILL),
  487.             is_local_b_val(curbp,VAL_FILL) ? "local" : "global" );
  488.     return(TRUE);
  489. }
  490.  
  491. /*
  492.  * Release storage of a REGEXVAL struct
  493.  */
  494. static REGEXVAL *
  495. free_regexval(register REGEXVAL *rp)
  496. {
  497.     if (rp != 0) {
  498.         FreeAndNull(rp->pat);
  499.         FreeAndNull(rp->reg);
  500.         free((char *)rp);
  501.     }
  502.     return 0;
  503. }
  504.  
  505. /*
  506.  * Allocate/set a new REGEXVAL struct
  507.  */
  508. REGEXVAL *
  509. new_regexval(const char *pattern, int magic)
  510. {
  511.     register REGEXVAL *rp;
  512.  
  513.     if ((rp = typealloc(REGEXVAL)) != 0) {
  514.         rp->pat = strmalloc(pattern);
  515.         if ((rp->reg = regcomp(rp->pat, magic)) == 0)
  516.             rp = free_regexval(rp);
  517.     }
  518.     return rp;
  519. }
  520.  
  521. /*
  522.  * Release storage of a VAL struct
  523.  */
  524. static void
  525. free_val(const struct VALNAMES *names, struct VAL *values)
  526. {
  527.     switch (names->type) {
  528.     case VALTYPE_STRING:
  529.         FreeAndNull(values->v.p);
  530.         break;
  531.     case VALTYPE_REGEX:
  532.         values->v.r = free_regexval(values->v.r);
  533.         break;
  534.     default:    /* nothing to free */
  535.         break;
  536.     }
  537. }
  538.  
  539. /*
  540.  * Copy a VAL-struct, preserving the sense of local/global.
  541.  */
  542. static int
  543. copy_val(struct VAL *dst, struct VAL *src)
  544. {
  545.     register int local = isLocalVal(src);
  546.  
  547.     *dst = *src;
  548.     if (local)
  549.         makeLocalVal(dst);
  550.     return local;
  551. }
  552.  
  553. void
  554. copy_mvals(
  555. int maximum,
  556. struct VAL *dst,
  557. struct VAL *src)
  558. {
  559.     register int    n;
  560.     for (n = 0; n < maximum; n++)
  561.         (void)copy_val(&dst[n], &src[n]);
  562. }
  563.  
  564. /*
  565.  * This is a special routine designed to save the values of local modes and to
  566.  * restore them.  The 'recompute_buffer()' procedure assumes that global modes
  567.  * do not change during the recomputation process (so there is no point in
  568.  * trying to convert any of those values to local ones).
  569.  */
  570. #if OPT_UPBUFF
  571. void
  572. save_vals(
  573. int maximum,
  574. struct VAL *gbl,
  575. struct VAL *dst,
  576. struct VAL *src)
  577. {
  578.     register int    n;
  579.     for (n = 0; n < maximum; n++)
  580.         if (copy_val(&dst[n], &src[n]))
  581.             make_global_val(src, gbl, n);
  582. }
  583. #endif
  584.  
  585. /*
  586.  * free storage used by local mode-values, called only when we are freeing
  587.  * all other storage associated with a buffer or window.
  588.  */
  589. void
  590. free_local_vals(
  591. const struct VALNAMES *names,
  592. struct VAL *gbl,
  593. struct VAL *val)
  594. {
  595.     register int    j;
  596.  
  597.     for (j = 0; names[j].name != 0; j++) {
  598.         if (is_local_val(val,j)) {
  599.             make_global_val(val, gbl, j);
  600.             free_val(names+j, val+j);
  601.         }
  602.     }
  603. }
  604.  
  605. /*
  606.  * Convert a string to boolean, checking for errors
  607.  */
  608. static int
  609. string_to_bool(const char *base, int *np)
  610. {
  611.     if (is_truem(base))
  612.         *np = TRUE;
  613.     else if (is_falsem(base))
  614.         *np = FALSE;
  615.     else {
  616.         mlforce("[Not a boolean: '%s']", base);
  617.         return FALSE;
  618.     }
  619.     return TRUE;
  620. }
  621.  
  622. /*
  623.  * Convert a string to number, checking for errors
  624.  */
  625. int
  626. string_to_number(const char *from, int *np)
  627. {
  628.     long n;
  629.     char *p;
  630.  
  631.     /* accept decimal, octal, or hex */
  632.     n = strtol(from, &p, 0);
  633.     if (p == from || *p != EOS) {
  634.         mlforce("[Not a number: '%s']", from);
  635.         return FALSE;
  636.     }
  637.     *np = (int)n;
  638.     return TRUE;
  639. }
  640.  
  641. /*
  642.  * Validate a 'glob' mode-value.  It is either a boolean, or it must be a
  643.  * pipe-expression with exactly one "%s" embedded (no other % characters,
  644.  * unless escaped).  That way, we can use the string to format the pipe
  645.  * command.
  646.  */
  647. #if defined(GMD_GLOB) || defined(GVAL_GLOB)
  648. static int
  649. legal_glob_mode(const char *base)
  650. {
  651. #ifdef GVAL_GLOB    /* string */
  652.     if (isShellOrPipe(base)) {
  653.         register const char *s = base;
  654.         int    count = 0;
  655.         while (*s != EOS) {
  656.             if (*s == '%') {
  657.                 if (*++s != '%') {
  658.                     if (*s == 's')
  659.                         count++;
  660.                     else
  661.                         count = 2;
  662.                 }
  663.             }
  664.             if (*s != EOS)
  665.                 s++;
  666.         }
  667.         if (count == 1)
  668.             return TRUE;
  669.     }
  670. #endif
  671.     if (!strcmp(base, "off")
  672.      || !strcmp(base, "on"))
  673.          return TRUE;
  674.  
  675.     mlforce("[Illegal value for glob: '%s']", base);
  676.     return FALSE;
  677. }
  678. #endif
  679.  
  680. /*
  681.  * FSM stands for fixed string mode, so called because the strings which the
  682.  * user is permitted to enter are non-arbitrary (fixed).
  683.  *
  684.  * It is meant to handle the following sorts of things:
  685.  *
  686.  *     :set popup-choices off
  687.  *     :set popup-choices immediate
  688.  *     :set popup-choices delayed
  689.  *
  690.  *     :set error quiet
  691.  *     :set error beep
  692.  *     :set error flash
  693.  */
  694. #if OPT_ENUM_MODES
  695.  
  696. #if NEVER
  697. FSM_CHOICES fsm_error[] = {
  698.     { "beep",      1},
  699.     { "flash",     2},
  700.     { "quiet",     0},
  701.     END_CHOICES
  702. };
  703. #endif
  704.  
  705. static
  706. struct FSM fsm_tbl[] = {
  707.     { "*bool",           fsm_bool_choices  },
  708. #if OPT_COLOR_CHOICES
  709.     { "fcolor",          fsm_color_choices },
  710.     { "bcolor",          fsm_color_choices },
  711. #endif
  712. #if OPT_POPUP_CHOICES
  713.     { "popup-choices",   fsm_popup_choices },
  714. #endif
  715. #if NEVER
  716.     { "error",           fsm_error },
  717. #endif
  718. #if OPT_BACKUP_CHOICES
  719.     { "backup-style",    fsm_backup_choices },
  720. #endif
  721. #if OPT_HILITE_CHOICES
  722.     { "visual-matches",  fsm_hilite_choices },
  723. #endif
  724.     { "mini-hilite",     fsm_hilite_choices },
  725. };
  726.  
  727. static int fsm_idx;
  728.  
  729. static int
  730. choice_to_code (const FSM_CHOICES *choices, const char *name)
  731. {
  732.     int code = ENUM_ILLEGAL;
  733.     register int i;
  734.     char    temp[64];
  735.     (void)mklower(strncpy0(temp, name, sizeof(temp)));
  736.  
  737.     for (i = 0; choices[i].choice_name != 0; i++) {
  738.         if (strcmp(temp, choices[i].choice_name) == 0) {
  739.             code = choices[i].choice_code;
  740.             break;
  741.         }
  742.     }
  743.     return code;
  744. }
  745.  
  746. static const char *
  747. choice_to_name (const FSM_CHOICES *choices, int code)
  748. {
  749.     const char *name = 0;
  750.     register int i;
  751.  
  752.     for (i = 0; choices[i].choice_name != 0; i++) {
  753.         if (choices[i].choice_code == code) {
  754.             name = choices[i].choice_name;
  755.             break;
  756.         }
  757.     }
  758.     return name;
  759. }
  760.  
  761. static const FSM_CHOICES *
  762. name_to_choices (const struct VALNAMES *names)
  763. {
  764.     register SIZE_T i;
  765.  
  766.     for (i = 1; i < TABLESIZE(fsm_tbl); i++)
  767.         if (strcmp(fsm_tbl[i].mode_name, names->name) == 0)
  768.             return fsm_tbl[i].choices;
  769.  
  770.     return 0;
  771. }
  772.  
  773. static int
  774. is_fsm(const struct VALNAMES *names)
  775. {
  776.     register SIZE_T i;
  777.  
  778.     if (names->type == VALTYPE_ENUM
  779.      || names->type == VALTYPE_STRING) {
  780.         for (i = 1; i < TABLESIZE(fsm_tbl); i++) {
  781.             if (strcmp(fsm_tbl[i].mode_name, names->name) == 0) {
  782.                 fsm_idx = (int)i;
  783.                 return TRUE;
  784.             }
  785.         }
  786.     } else if (is_bool_type(names->type)) {
  787.         fsm_idx = 0;
  788.         return TRUE;
  789.     }
  790.     fsm_idx = -1;
  791.     return FALSE;
  792. }
  793.  
  794. /*
  795.  * Test if we're processing an enum-valued mode.  If so, lookup the mode value.
  796.  * We'll allow a numeric index also (e.g., for colors).  Note that we're
  797.  * returning the table-value in that case, so we'll have to ensure that we
  798.  * don't corrupt the table.
  799.  */
  800. static const char *
  801. legal_fsm(const char *val)
  802. {
  803.     if (fsm_idx >= 0) {
  804.         int i;
  805.         int idx = fsm_idx;
  806.         const FSM_CHOICES *p = fsm_tbl[idx].choices;
  807.         const char *s;
  808.  
  809.         if (isDigit(*val)) {
  810.             if (!string_to_number(val, &i))
  811.                 return 0;
  812.             if ((s = choice_to_name(p, i)) != 0)
  813.                 return s;
  814.         } else {
  815.             if (choice_to_code(p, val) != ENUM_ILLEGAL)
  816.                 return val;
  817.         }
  818.         mlforce("[Illegal value for %s: '%s']",
  819.             fsm_tbl[idx].mode_name,
  820.             val);
  821.         return 0;
  822.     }
  823.     return val;
  824. }
  825.  
  826. static int
  827. fsm_complete(int c, char *buf, unsigned *pos)
  828. {
  829.     if (isDigit(*buf)) {        /* allow numbers for colors */
  830.     if (c != NAMEC)          /* put it back (cf: kbd_complete) */
  831.         unkeystroke(c);
  832.     return isSpace(c);
  833.     }
  834.     return kbd_complete(FALSE, c, buf, pos,
  835.                         (const char *)(fsm_tbl[fsm_idx].choices),
  836.             sizeof (FSM_CHOICES) );
  837. }
  838. #endif    /* OPT_ENUM_MODES */
  839.  
  840. /*
  841.  * Lookup the mode named with 'cp[]' and adjust its value.
  842.  */
  843. int
  844. adjvalueset(
  845. const char *cp,            /* name of the mode we are changing */
  846. int setting,            /* true if setting, false if unsetting */
  847. int global,
  848. VALARGS *args)            /* symbol-table entry for the mode */
  849. {
  850.     const struct VALNAMES *names = args->names;
  851.     struct VAL     *values = args->local;
  852.     struct VAL     *globls = args->global;
  853.  
  854.     char prompt[NLINE];
  855.     char respbuf[NFILEN];
  856.     int no = !strncmp(cp, "no", 2);
  857.     const char *rp = NULL;
  858.     int status = TRUE;
  859.     int unsetting = !setting && !global;
  860.  
  861.     if (no && !is_bool_type(names->type))
  862.         return FALSE;        /* this shouldn't happen */
  863.  
  864.     /*
  865.      * Check if we're allowed to change this mode in the current context.
  866.      */
  867.     if ((names->side_effect != 0)
  868.      && !(*(names->side_effect))(args, (values==globls), TRUE)) {
  869.         return FALSE;
  870.      }
  871.  
  872.     /* get a value if we need one */
  873.     if ((end_string() == '=')
  874.      || (!is_bool_type(names->type) && !unsetting)) {
  875.         int    regex = (names->type == VALTYPE_REGEX);
  876.         int    opts = regex ? 0 : KBD_NORMAL;
  877.         int    eolchar = (names->type == VALTYPE_REGEX
  878.                 || names->type == VALTYPE_STRING) ? '\n' : ' ';
  879.         int    (*complete) (DONE_ARGS) = no_completion;
  880.  
  881.         respbuf[0] = EOS;
  882.         (void)lsprintf(prompt, "New %s %s: ",
  883.             cp,
  884.             regex ? "pattern" : "value");
  885.  
  886. #if OPT_ENUM_MODES
  887.         if (is_fsm(names))
  888.             complete = fsm_complete;
  889. #endif
  890.  
  891.         status = kbd_string(prompt, respbuf, sizeof(respbuf), eolchar,
  892.                        opts, complete);
  893.         if (status != TRUE)
  894.             return status;
  895.         if (!strlen(rp = respbuf))
  896.             return FALSE;
  897.     }
  898. #if OPT_HISTORY
  899.     else
  900.         hst_glue(' ');
  901. #endif
  902.     status = set_mode_value(cp, setting, global, args, rp);
  903.     TRACE(("...adjvalueset(%s)=%d\n", cp, status))
  904.  
  905.     return status;
  906. }
  907.  
  908. int
  909. set_mode_value(const char *cp, int setting, int global, VALARGS *args, const char *rp)
  910. {
  911.     const struct VALNAMES *names = args->names;
  912.     struct VAL     *values = args->local;
  913.     struct VAL     *globls = args->global;
  914.     REGEXVAL *r;
  915.  
  916.     struct VAL oldvalue;
  917.     int no = !strncmp(cp, "no", 2);
  918.     int nval, status = TRUE;
  919.     int unsetting = !setting && !global;
  920.     int changed = FALSE;
  921.  
  922.     if (rp == NULL) {
  923.         rp = no ? cp+2 : cp;
  924.     }
  925.     else {
  926.         if (no && !is_bool_type(names->type))
  927.             return FALSE;        /* this shouldn't happen */
  928.  
  929.         /*
  930.          * Check if we're allowed to change this mode in the current context.
  931.          */
  932.         if ((names->side_effect != 0)
  933.          && !(*(names->side_effect))(args, (values==globls), TRUE)) {
  934.             return FALSE;
  935.         }
  936.  
  937. #if defined(GMD_GLOB) || defined(GVAL_GLOB)
  938.         if (!strcmp(names->name, "glob")
  939.          && !legal_glob_mode(rp))
  940.             return FALSE;
  941. #endif
  942. #if OPT_ENUM_MODES
  943.         (void) is_fsm(names);        /* evaluated for its side effects */
  944.         if ((rp = legal_fsm(rp)) == 0)
  945.             return FALSE;
  946. #endif
  947.         /* Test after fsm, to allow translation */
  948.         if (is_bool_type(names->type)) {
  949.             if (!string_to_bool(rp, &setting))
  950.                 return FALSE;
  951.         }
  952.     }
  953.  
  954.     /* save, to simplify no-change testing */
  955.     (void)copy_val(&oldvalue, values);
  956.  
  957.     if (unsetting) {
  958.         make_global_val(values, globls, 0);
  959. #if OPT_MAJORMODE
  960.         switch(names->type) {
  961.         case VALTYPE_MAJOR:
  962.             if (values == globls)
  963.                 changed = enable_mmode(names->shortname, FALSE);
  964.             else
  965.                 changed = detach_mmode(curbp, names->shortname);
  966.             break;
  967.         }
  968. #endif
  969.     } else {
  970.         makeLocalVal(values);    /* make sure we point to result! */
  971.  
  972.         /* we matched a name -- set the value */
  973.         switch(names->type) {
  974. #if OPT_MAJORMODE
  975.         case VALTYPE_MAJOR:
  976.             values->vp->i = no ? !setting : setting;
  977.             if (values == globls) {
  978.                 changed = enable_mmode(names->shortname, values->vp->i);
  979.             } else {
  980.                 changed = no
  981.                     ? detach_mmode(curbp, names->shortname)
  982.                     : attach_mmode(curbp, names->shortname);
  983.             }
  984.             break;
  985. #endif
  986.         case VALTYPE_BOOL:
  987.             values->vp->i = no ? !setting : setting;
  988.             break;
  989.  
  990.         case VALTYPE_ENUM:
  991. #if OPT_ENUM_MODES
  992.             {
  993.                 const FSM_CHOICES *fp = name_to_choices(names);
  994.  
  995.                 if (isDigit(*rp)) {
  996.                     if (!string_to_number(rp, &nval))
  997.                         return FALSE;
  998.                     if (choice_to_name(fp, nval) == 0)
  999.                         nval = ENUM_ILLEGAL;
  1000.                 } else {
  1001.                     nval = choice_to_code(fp, rp);
  1002.                 }
  1003.                 if (nval == ENUM_ILLEGAL) {
  1004.                     mlforce("[Not a legal enum-index: %s]",
  1005.                         rp);
  1006.                     return FALSE;
  1007.                 }
  1008.             }
  1009.             values->vp->i = nval;
  1010.             break;
  1011. #endif /* OPT_ENUM_MODES */
  1012.  
  1013.         case VALTYPE_INT:
  1014.             if (!string_to_number(rp, &nval))
  1015.                 return FALSE;
  1016.             values->vp->i = nval;
  1017.             break;
  1018.  
  1019.         case VALTYPE_STRING:
  1020.             values->vp->p = strmalloc(rp);
  1021.             break;
  1022.  
  1023.         case VALTYPE_REGEX:
  1024.             if ((r = new_regexval(rp, TRUE)) == 0) {
  1025.                 values->vp->r = new_regexval("", TRUE);
  1026.                 return FALSE;
  1027.             }
  1028.             values->vp->r = r;
  1029.             break;
  1030.  
  1031.         default:
  1032.             mlforce("BUG: bad type %s %d", names->name, names->type);
  1033.             return FALSE;
  1034.         }
  1035.     }
  1036.  
  1037.     /*
  1038.      * Set window flags (to force the redisplay as needed), and apply
  1039.      * side-effects.
  1040.      */
  1041.     status = TRUE;
  1042.     if (!same_val(names, values, &oldvalue))
  1043.         changed = TRUE;
  1044.  
  1045.     if (changed
  1046.      && (names->side_effect != 0)
  1047.      && !(*(names->side_effect))(args, (values==globls), FALSE))
  1048.         status = FALSE;
  1049.  
  1050.     if (isLocalVal(&oldvalue)
  1051.      && (values != globls))
  1052.         free_val(names, &oldvalue);
  1053.  
  1054.     return status;
  1055. }
  1056.  
  1057. /* ARGSUSED */
  1058. int
  1059. listmodes(int f, int n GCC_UNUSED)
  1060. {
  1061.     register WINDOW *wp = curwp;
  1062.     register int s;
  1063.  
  1064.     s = liststuff(SETTINGS_BufName, FALSE, makemodelist,f,(void *)wp);
  1065.     /* back to the buffer whose modes we just listed */
  1066.     if (swbuffer(wp->w_bufp))
  1067.         curwp = wp;
  1068.     return s;
  1069. }
  1070.  
  1071. /*
  1072.  * The 'mode_complete()' and 'mode_eol()' functions are invoked from
  1073.  * 'kbd_reply()' to setup the mode-name completion and query displays.
  1074.  */
  1075. static int
  1076. mode_complete(DONE_ARGS)
  1077. {
  1078.     init_my_mode_list();
  1079.  
  1080.     return kbd_complete(FALSE, c, buf, pos,
  1081.         (const char *)&my_mode_list[0], sizeof(my_mode_list[0]));
  1082. }
  1083.  
  1084. int
  1085. /*ARGSUSED*/
  1086. mode_eol(const char * buffer GCC_UNUSED, unsigned cpos GCC_UNUSED, int c, int eolchar)
  1087. {
  1088.     return (c == ' ' || c == eolchar);
  1089. }
  1090.  
  1091. static int
  1092. lookup_valnames(const char *rp, const struct VALNAMES *table)
  1093. {
  1094.     register int j;
  1095.  
  1096.     for (j = 0; table[j].name != 0; j++) {
  1097.         if (!strcmp(rp, table[j].name)
  1098.          || !strcmp(rp, table[j].shortname)) {
  1099.             return j;
  1100.         }
  1101.     }
  1102.     return -1;
  1103. }
  1104.  
  1105. int
  1106. find_mode(const char *mode, int global, VALARGS *args)
  1107. {
  1108.     register const char *rp = !strncmp(mode, "no", 2) ? mode+2 : mode;
  1109.     register int    mode_class;
  1110.     register int    j;
  1111.  
  1112.     TRACE(("find_mode(%s) %s\n", mode, global ? "global" : "local"))
  1113.  
  1114.     for (mode_class = 0; mode_class < MODE_CLASSES; mode_class++) {
  1115.         memset(args, 0, sizeof(*args));
  1116.         switch (mode_class) {
  1117.         default: /* universal modes */
  1118.             args->names  = g_valnames;
  1119.             args->global = global_g_values.gv;
  1120.             args->local  = (global != FALSE)
  1121.                 ? args->global
  1122.                 : (struct VAL *)0;
  1123.             break;
  1124.         case 1:    /* buffer modes */
  1125.             args->names  = b_valnames;
  1126.             args->global = global_b_values.bv;
  1127.             args->local  = (global == TRUE)
  1128.                 ? args->global
  1129.                 : ((curbp != 0)
  1130.                     ? curbp->b_values.bv
  1131.                     : (struct VAL *)0);
  1132.             break;
  1133.         case 2:    /* window modes */
  1134.             args->names  = w_valnames;
  1135.             args->global = global_w_values.wv;
  1136.             args->local  = (global == TRUE)
  1137.                 ? args->global
  1138.                 : ((curwp != 0)
  1139.                     ? curwp->w_values.wv
  1140.                     : (struct VAL *)0);
  1141.             break;
  1142. #if OPT_MAJORMODE
  1143.         case 3: /* major modes */
  1144.             args->names  = major_valnames;
  1145.             args->global = major_g_vals;
  1146.             args->local  = (global == TRUE)
  1147.                 ? args->global
  1148.                 : ((curbp != 0)
  1149.                     ? major_l_vals
  1150.                     : (struct VAL *)0);
  1151.             break;
  1152.         case 4: /* major submodes (qualifiers) */
  1153.             if (my_majormodes != 0) {
  1154.                 size_t n = strlen(rp);
  1155.  
  1156.                 for (j = 0; my_majormodes[j].name; j++) {
  1157.                     MAJORMODE_LIST *p = my_majormodes+j;
  1158.                     size_t len = strlen(p->name);
  1159.  
  1160.                     if (n >= len
  1161.                      && !strncmp(rp, p->name, len)
  1162.                      && (lookup_valnames(rp, p->qual)) >= 0) {
  1163.                         args->names  = p->qual;
  1164.                         args->global = p->data->mm.mv;
  1165.                         args->local  = (global != FALSE)
  1166.                             ? args->global
  1167.                             : (struct VAL *)0;
  1168.                         break;
  1169.                     }
  1170.                 }
  1171.             }
  1172.             break;
  1173. #endif
  1174.         }
  1175.         if (args->names != 0
  1176.          && args->local != 0) {
  1177.             if ((j = lookup_valnames(rp, args->names)) >= 0) {
  1178.                 args->names  += j;
  1179.                 args->local  += j;
  1180.                 args->global += j;
  1181.                 TRACE(("...found class %d %s\n", mode_class, rp))
  1182. #if OPT_MAJORMODE
  1183.                 if (mode_class == 3) {
  1184.                     char *it = (curbp->majr != 0)
  1185.                         ? curbp->majr->name
  1186.                         : "?";
  1187.                     make_global_val(args->local,args->global,0);
  1188.                     if (global) {
  1189.                         MAJORMODE_LIST *ptr =
  1190.                             lookup_mm_list(it);
  1191.                         args->local[0].v.i =
  1192.                             (ptr != 0 && ptr->flag);
  1193.                         ;
  1194.                     } else {
  1195.                         char temp[NSTRING];
  1196.                         majorname(temp, it, TRUE);
  1197.                         make_local_val(args->local,0);
  1198.                         args->local[0].v.i = !strcmp(temp, rp);
  1199.                     }
  1200.                 }
  1201. #endif
  1202.                 return TRUE;
  1203.             }
  1204.         }
  1205.     }
  1206. #if OPT_MAJORMODE
  1207.     /* major submodes (buffers) */
  1208.     if (my_majormodes != 0) {
  1209.         int k = 0;
  1210.         size_t n = strlen(rp);
  1211.  
  1212.         for (j = 0; my_majormodes[j].name; j++) {
  1213.             MAJORMODE_LIST *p = my_majormodes+j;
  1214.             size_t len = strlen(p->name);
  1215.  
  1216.             if (n >= len
  1217.              && !strncmp(rp, p->name, len)
  1218.              && (k = lookup_valnames(rp+len+(rp[len]=='-'), b_valnames)) >= 0
  1219.              && is_local_val(p->data->mb.bv,k)) {
  1220.                 TRACE(("...found submode %s\n", b_valnames[k].name))
  1221.                 if (global == FALSE) {
  1222.                     if (curbp != 0
  1223.                      && (curbp->majr == 0
  1224.                       || strcmp(curbp->majr->name, p->name))) {
  1225.                         TRACE(("...not applicable\n"))
  1226.                         return FALSE;
  1227.                     }
  1228.                     args->names  = b_valnames + k;
  1229.                     args->global = p->data->mb.bv + k;
  1230.                     args->local  = ((curbp != 0)
  1231.                             ? curbp->b_values.bv + k
  1232.                             : (struct VAL *)0);
  1233.                 } else {
  1234.                     args->names  = b_valnames + k;
  1235.                     args->global = p->data->mb.bv + k;
  1236.                     args->local  = args->global;
  1237.                 }
  1238.                 return TRUE;
  1239.             }
  1240.         }
  1241.     }
  1242. #endif
  1243.     TRACE(("...not found\n"))
  1244.     return FALSE;
  1245. }
  1246.  
  1247. /*
  1248.  * Process a single mode-setting
  1249.  */
  1250. static int
  1251. do_a_mode(int kind, int global)
  1252. {
  1253.     VALARGS    args;
  1254.     register int    s;
  1255.     static TBUFF *cbuf;     /* buffer to receive mode name into */
  1256.  
  1257.     /* prompt the user and get an answer */
  1258.     tb_scopy(&cbuf, "");
  1259.     if ((s = kbd_reply(
  1260.         global    ? "Global value: "
  1261.             : "Local value: ",
  1262.         &cbuf,
  1263.         mode_eol, '=', KBD_NORMAL, mode_complete)) != TRUE)
  1264.         return ((s == FALSE) ? SORTOFTRUE : s);
  1265.  
  1266.     if (!strcmp(tb_values(cbuf), "all")) {
  1267.         hst_glue(' ');
  1268.         return listmodes(FALSE,1);
  1269.     }
  1270.  
  1271.     if ((s = find_mode(tb_values(cbuf), global, &args)) != TRUE) {
  1272. #if OPT_EVAL
  1273.         if (!global && (s = find_mode(tb_values(cbuf), TRUE, &args)) == TRUE) {
  1274.             mlforce("[Not a local mode: \"%s\"]", tb_values(cbuf));
  1275.             return FALSE;
  1276.         }
  1277.         return set_variable(tb_values(cbuf));
  1278. #else
  1279.         mlforce("[Not a legal set option: \"%s\"]", tb_values(cbuf));
  1280. #endif
  1281.     } else if ((s = adjvalueset(tb_values(cbuf), kind, global, &args)) != 0) {
  1282.         if (s == TRUE)
  1283.             mlerase();    /* erase the junk */
  1284.         return s;
  1285.     }
  1286.  
  1287.     return FALSE;
  1288. }
  1289.  
  1290. /*
  1291.  * Process the list of mode-settings
  1292.  */
  1293. static int
  1294. adjustmode(    /* change the editor mode status */
  1295. int kind,    /* true = set,        false = delete */
  1296. int global)    /* true = global flag,    false = current buffer flag */
  1297. {
  1298.     int s;
  1299.     int anything = 0;
  1300.  
  1301.     if (kind && global && isreturn(end_string()))
  1302.         return listmodes(TRUE,1);
  1303.  
  1304.     while (((s = do_a_mode(kind, global)) == TRUE) && (end_string() == ' '))
  1305.         anything++;
  1306.     if ((s == SORTOFTRUE) && anything) /* fix for trailing whitespace */
  1307.         return TRUE;
  1308.  
  1309.     /* if the settings are up, redisplay them */
  1310.     relist_settings();
  1311.     relist_majormodes();
  1312.  
  1313.     if (curbp) {
  1314.         curtabval = tabstop_val(curbp);
  1315.     }
  1316.  
  1317.     return s;
  1318. }
  1319.  
  1320. /*
  1321.  * Buffer-animation for [Settings]
  1322.  */
  1323. #if OPT_UPBUFF
  1324. static int
  1325. show_Settings(BUFFER *bp)
  1326. {
  1327.     b_clr_obsolete(bp);
  1328.     return listmodes(FALSE, 1);
  1329. }
  1330.  
  1331. static void
  1332. relist_settings(void)
  1333. {
  1334.     update_scratch(SETTINGS_BufName, show_Settings);
  1335. }
  1336. #endif    /* OPT_UPBUFF */
  1337.  
  1338. /* ARGSUSED */
  1339. int
  1340. setlocmode(int f GCC_UNUSED, int n GCC_UNUSED)    /* prompt and set an editor mode */
  1341. {
  1342.     return adjustmode(TRUE, FALSE);
  1343. }
  1344.  
  1345. /* ARGSUSED */
  1346. int
  1347. dellocmode(int f GCC_UNUSED, int n GCC_UNUSED)    /* prompt and delete an editor mode */
  1348. {
  1349.     return adjustmode(FALSE, FALSE);
  1350. }
  1351.  
  1352. /* ARGSUSED */
  1353. int
  1354. setglobmode(int f GCC_UNUSED, int n GCC_UNUSED)    /* prompt and set a global editor mode */
  1355. {
  1356.     return adjustmode(TRUE, TRUE);
  1357. }
  1358.  
  1359. /* ARGSUSED */
  1360. int
  1361. delglobmode(int f GCC_UNUSED, int n GCC_UNUSED)    /* prompt and delete a global editor mode */
  1362. {
  1363.     return adjustmode(FALSE, TRUE);
  1364. }
  1365.  
  1366. /*
  1367.  * The following functions are invoked to carry out side effects of changing
  1368.  * modes.
  1369.  */
  1370. /*ARGSUSED*/
  1371. int
  1372. chgd_autobuf(VALARGS *args GCC_UNUSED, int glob_vals, int testing GCC_UNUSED)
  1373. {
  1374.     if (glob_vals)
  1375.         sortlistbuffers();
  1376.     return TRUE;
  1377. }
  1378.  
  1379. /*ARGSUSED*/
  1380. int
  1381. chgd_buffer(VALARGS *args GCC_UNUSED, int glob_vals, int testing GCC_UNUSED)
  1382. {
  1383.     if (!glob_vals) {    /* i.e., ":setl" */
  1384.         if (curbp == 0)
  1385.             return FALSE;
  1386.         b_clr_counted(curbp);
  1387.         (void)bsizes(curbp);
  1388.     }
  1389.     return TRUE;
  1390. }
  1391.  
  1392. int
  1393. chgd_charset(VALARGS *args, int glob_vals, int testing)
  1394. {
  1395.     if (!testing) {
  1396.         charinit();
  1397.     }
  1398.     return chgd_window(args, glob_vals, testing);
  1399. }
  1400.  
  1401. #if OPT_COLOR
  1402. int
  1403. chgd_color(VALARGS *args, int glob_vals, int testing)
  1404. {
  1405.     if (!testing) {
  1406.         if (&args->local->vp->i == &gfcolor)
  1407.             TTforg(gfcolor);
  1408.         else if (&args->local->vp->i == &gbcolor)
  1409.             TTbacg(gbcolor);
  1410.         set_winflags(glob_vals, WFHARD|WFCOLR);
  1411.         vile_refresh(FALSE,0);
  1412.     }
  1413.     return TRUE;
  1414. }
  1415.  
  1416. #if OPT_EVAL
  1417. static void
  1418. set_fsm_choice(const char *name, const FSM_CHOICES *choices)
  1419. {
  1420.     size_t n;
  1421.     for (n = 0; n < TABLESIZE(fsm_tbl); n++) {
  1422.         if (!strcmp(name, fsm_tbl[n].mode_name)) {
  1423.             fsm_tbl[n].choices = choices;
  1424.             break;
  1425.         }
  1426.     }
  1427. }
  1428. #endif    /* OPT_EVAL */
  1429.  
  1430. static int
  1431. reset_color(int n)
  1432. {
  1433.     if (global_g_val(n) > ncolors) {
  1434.         set_global_g_val(n, global_g_val(n) % ncolors);
  1435.         return TRUE;
  1436.     }
  1437.     return FALSE;
  1438. }
  1439.  
  1440. #if OPT_ENUM_MODES
  1441. static FSM_CHOICES *my_colors;
  1442. static FSM_CHOICES *my_hilite;
  1443. #endif
  1444.  
  1445. /*
  1446.  * Set the number of colors to a subset of that which is configured.  The main
  1447.  * use for this is to switch between 16-colors and 8-colors, though it should
  1448.  * work for setting any power of 2 up to the NCOLORS value.
  1449.  */
  1450. int set_ncolors(int n)
  1451. {
  1452.     static int initialized;
  1453. #if OPT_ENUM_MODES
  1454.     const FSM_CHOICES *the_colors, *the_hilite;
  1455.     size_t s, d;
  1456. #endif
  1457.  
  1458.     if (n > NCOLORS || n < 2)
  1459.         return FALSE;
  1460.     if (!initialized)
  1461.         initialized = n;
  1462.     if (n > initialized)
  1463.         return FALSE;
  1464.     ncolors = n;
  1465.     if (reset_color(GVAL_FCOLOR)
  1466.      || reset_color(GVAL_BCOLOR)) {
  1467.         vile_refresh(FALSE,0);
  1468.     }
  1469.  
  1470. #if OPT_ENUM_MODES
  1471.     if (ncolors == NCOLORS) {
  1472.         the_colors = fsm_color_choices;
  1473.         the_hilite = fsm_hilite_choices;
  1474.     } else {
  1475.         my_colors = typecallocn(FSM_CHOICES,TABLESIZE(fsm_color_choices));
  1476.         my_hilite = typecallocn(FSM_CHOICES,TABLESIZE(fsm_hilite_choices));
  1477.         the_colors = my_colors;
  1478.         the_hilite = my_hilite;
  1479.         for (s = d = 0; s < TABLESIZE(fsm_color_choices)-1; s++) {
  1480.             my_colors[d] = fsm_color_choices[s];
  1481.             if (my_colors[d].choice_code > 0) {
  1482.                 if (!(my_colors[d].choice_code %= ncolors))
  1483.                     continue;
  1484.             }
  1485.             if (strncmp(my_colors[d].choice_name, "bright", 6))
  1486.                 d++;
  1487.         }
  1488.         my_colors[d].choice_name = 0;
  1489.  
  1490.         for (s = d = 0; s < TABLESIZE(fsm_hilite_choices)-1; s++) {
  1491.             my_hilite[d] = fsm_hilite_choices[s];
  1492.             if (my_hilite[d].choice_code & VASPCOL) {
  1493.                 unsigned code = my_hilite[d].choice_code % NCOLORS;
  1494.                 if (code != 0) {
  1495.                     if ((code %= ncolors) == 0)
  1496.                         continue;
  1497.                     my_hilite[d].choice_code = VASPCOL | code;
  1498.                 }
  1499.                 if (strncmp(my_hilite[d].choice_name, "bright", 6))
  1500.                     d++;
  1501.             } else {
  1502.                 d++;
  1503.             }
  1504.         }
  1505.         my_hilite[d].choice_name = 0;
  1506.     }
  1507.     set_fsm_choice("fcolor", the_colors);
  1508.     set_fsm_choice("bcolor", the_colors);
  1509.     set_fsm_choice("visual-matches", the_hilite);
  1510.     set_fsm_choice("mini-hilite", the_hilite);
  1511. #endif /* OPT_ENUM_MODES */
  1512.     return TRUE;
  1513. }
  1514. #endif    /* OPT_COLOR */
  1515.  
  1516.     /* Report mode that cannot be changed */
  1517. /*ARGSUSED*/
  1518. int
  1519. chgd_disabled(VALARGS *args, int glob_vals GCC_UNUSED, int testing GCC_UNUSED)
  1520. {
  1521.     mlforce("[Cannot change \"%s\" ]", args->names->name);
  1522.     return FALSE;
  1523. }
  1524.  
  1525.     /* Change "fences" mode */
  1526. /*ARGSUSED*/
  1527. int
  1528. chgd_fences(VALARGS *args, int glob_vals GCC_UNUSED, int testing)
  1529. {
  1530.     if (!testing) {
  1531.         /* was even number of fence pairs specified? */
  1532.         char *value = args->local->v.p;
  1533.         size_t len = strlen(value);
  1534.  
  1535.         if (len & 1) {
  1536.             value[len-1] = EOS;
  1537.             mlwrite(
  1538.             "[Fence-pairs not in pairs:  truncating to \"%s\"",
  1539.                 value);
  1540.             return FALSE;
  1541.         }
  1542.     }
  1543.     return TRUE;
  1544. }
  1545.  
  1546.     /* Change a "major" mode */
  1547. int
  1548. chgd_major(VALARGS *args, int glob_vals, int testing)
  1549. {
  1550.     /* prevent major-mode changes for scratch-buffers */
  1551.     if (testing) {
  1552.         if (!glob_vals) {
  1553.             if (b_is_scratch(curbp))
  1554.                 return chgd_disabled(args, glob_vals, testing);
  1555.         }
  1556.     } else {
  1557.         set_winflags(glob_vals, WFMODE);
  1558.     }
  1559.     return TRUE;
  1560. }
  1561.  
  1562.     /* Change a major mode that affects the windows on the buffer */
  1563. int
  1564. chgd_major_w(VALARGS *args, int glob_vals, int testing)
  1565. {
  1566.     if (testing) {
  1567.         if (!chgd_major(args, glob_vals, testing))
  1568.             return FALSE;
  1569.         return chgd_window(args, glob_vals, testing);
  1570.     }
  1571.  
  1572.     set_winflags(glob_vals, WFHARD|WFMODE);
  1573.     return TRUE;
  1574. }
  1575.  
  1576.     /* Change something on the mode/status line */
  1577. /*ARGSUSED*/
  1578. int
  1579. chgd_status(VALARGS *args GCC_UNUSED, int glob_vals, int testing)
  1580. {
  1581.     if (!testing) {
  1582.         set_winflags(glob_vals, WFSTAT);
  1583.     }
  1584.     return TRUE;
  1585. }
  1586.  
  1587.     /* Change a mode that affects the windows on the buffer */
  1588. /*ARGSUSED*/
  1589. int
  1590. chgd_window(VALARGS *args GCC_UNUSED, int glob_vals, int testing)
  1591. {
  1592.     if (!testing) {
  1593.         set_winflags(glob_vals, WFHARD);
  1594.     }
  1595.     return TRUE;
  1596. }
  1597.  
  1598.     /* Change the working mode */
  1599. #if OPT_WORKING
  1600. /*ARGSUSED*/
  1601. int
  1602. chgd_working(VALARGS *args GCC_UNUSED, int glob_vals, int testing GCC_UNUSED)
  1603. {
  1604.     if (glob_vals)
  1605.         imworking(0);
  1606.     return TRUE;
  1607. }
  1608. #endif
  1609.  
  1610.     /* Change the xterm-mouse mode */
  1611. /*ARGSUSED*/
  1612. int
  1613. chgd_xterm(VALARGS *args GCC_UNUSED, int glob_vals, int testing GCC_UNUSED)
  1614. {
  1615. #if    OPT_XTERM
  1616.     if (glob_vals) {
  1617.         int    new_state = global_g_val(GMDXTERM_MOUSE);
  1618.         set_global_g_val(GMDXTERM_MOUSE,TRUE);
  1619.         if (!new_state)    TTkclose();
  1620.         else        TTkopen();
  1621.         set_global_g_val(GMDXTERM_MOUSE,new_state);
  1622.     }
  1623. #endif
  1624.     return TRUE;
  1625. }
  1626.  
  1627.     /* Change a mode that affects the search-string highlighting */
  1628. /*ARGSUSED*/
  1629. int
  1630. chgd_hilite(VALARGS *args GCC_UNUSED, int glob_vals GCC_UNUSED, int testing)
  1631. {
  1632.     if (!testing)
  1633.         attrib_matches();
  1634.     return TRUE;
  1635. }
  1636.  
  1637. /*--------------------------------------------------------------------------*/
  1638.  
  1639. #if OPT_EVAL || OPT_MAJORMODE
  1640. /*
  1641.  * Test for mode-names that we'll not show in the variable name-completion.
  1642.  */
  1643. int
  1644. is_varmode (const char *name)
  1645. {
  1646.     return (strncmp(name, "no", 2)
  1647.        &&   strcmp(name, "all"));
  1648. }
  1649.  
  1650. static int
  1651. is_identifier (const char *name)
  1652. {
  1653.     int first = TRUE;;
  1654.  
  1655.     while (*name != EOS) {
  1656.         if (first) {
  1657.             if (!isAlpha(*name))
  1658.                 return FALSE;
  1659.             first = FALSE;
  1660.         } else if (!isident(*name))
  1661.             return FALSE;
  1662.         name++;
  1663.     }
  1664.     return TRUE;
  1665. }
  1666.  
  1667. /*
  1668.  * Returns the current number of items in the list of modes
  1669.  */
  1670. static size_t
  1671. count_modes (void)
  1672. {
  1673.     size_t n;
  1674.  
  1675.     init_my_mode_list();
  1676.  
  1677.     for (n = 0; my_mode_list[n] != 0; n++)
  1678.         ;
  1679.     return n;
  1680. }
  1681.  
  1682. /*
  1683.  * Return a list of only the modes that can be set with ":setv", ignoring
  1684.  * artifacts such as "all".
  1685.  */
  1686. const char *const *
  1687. list_of_modes (void)
  1688. {
  1689.     if (my_varmodes == 0) {
  1690.         const char *const *s;
  1691.         const char **d;
  1692.         size_t n = count_modes();
  1693.         my_varmodes = typeallocn(const char *, n + 1);
  1694.         for (s = my_mode_list, d = my_varmodes; (*d = *s) != 0; s++) {
  1695.             if (is_varmode(*d)) {
  1696.                 d++;
  1697.             }
  1698.         }
  1699.     }
  1700.     return my_varmodes;
  1701. }
  1702. #endif /* OPT_EVAL || OPT_MAJORMODE */
  1703.  
  1704. /*--------------------------------------------------------------------------*/
  1705.  
  1706. #if OPT_MAJORMODE
  1707. static int
  1708. ok_submode(const char *name)
  1709. {
  1710.     /* like is_varmode, but allow "no" prefix */
  1711.     return strcmp(name, "all") != 0 ? TRUE : FALSE;
  1712. }
  1713.  
  1714. /* format the name of a majormode's qualifier */
  1715. static char *
  1716. per_major(char *dst, const char *majr, int code, int brief)
  1717. {
  1718.     if (brief) {
  1719.         (void) lsprintf(dst, "%s%s", majr, m_valnames[code].shortname);
  1720.     } else {
  1721.         (void) lsprintf(dst, "%s-%s", majr, m_valnames[code].name);
  1722.     }
  1723.     return dst;
  1724. }
  1725.  
  1726. /* format the name of a majormode's submode */
  1727. static char *
  1728. per_submode(char *dst, const char *majr, int code, int brief)
  1729. {
  1730.     if (brief) {
  1731.         if (!strcmp(b_valnames[code].shortname, "X")) {
  1732.             *dst = EOS;
  1733.             return 0;
  1734.         }
  1735.         (void) lsprintf(dst, "%s%s", majr, b_valnames[code].shortname);
  1736.     } else {
  1737.         (void) lsprintf(dst, "%s-%s", majr, b_valnames[code].name);
  1738.     }
  1739.     return dst;
  1740. }
  1741.  
  1742. static char *TheMajor;
  1743.  
  1744. static const char *
  1745. ModeName(const char *name)
  1746. {
  1747.     if (TheMajor != 0) {
  1748.         static char *dst;
  1749.         if (dst != 0)
  1750.             free(dst);
  1751.         dst = typeallocn(char, strlen(TheMajor) + strlen(name) + 3);
  1752.         (void) lsprintf(dst, "%s-%s", TheMajor, name);
  1753.         return dst;
  1754.     }
  1755.     return name;
  1756. }
  1757.  
  1758. /* format the name of a majormode */
  1759. static char *
  1760. majorname(char *dst, const char *majr, int flag)
  1761. {
  1762.     (void) lsprintf(dst, "%s%smode", flag ? "" : "no", majr);
  1763.     return dst;
  1764. }
  1765.  
  1766. /*
  1767.  * Returns the current number of items in the list of modes
  1768.  */
  1769. static size_t
  1770. count_majormodes (void)
  1771. {
  1772.     size_t n = 0;
  1773.  
  1774.     if (my_majormodes != 0) {
  1775.         for (n = 0; my_majormodes[n].name != 0; n++)
  1776.             ;
  1777.     }
  1778.     return n;
  1779. }
  1780.  
  1781. static int
  1782. found_per_submode(const char *majr, int code)
  1783. {
  1784.     size_t n;
  1785.     char temp[NSTRING];
  1786.  
  1787.     init_my_mode_list();
  1788.  
  1789.     (void) per_submode(temp, majr, code, TRUE);
  1790.     for (n = 0; my_mode_list[n] != 0; n++) {
  1791.         if (!strcmp(my_mode_list[n], temp))
  1792.             return TRUE;
  1793.     }
  1794.     return FALSE;
  1795. }
  1796.  
  1797. /*
  1798.  * Insert 'name' into 'my_mode_list[]', which has 'count' entries.
  1799.  */
  1800. static size_t
  1801. insert_per_major(size_t count, const char *name)
  1802. {
  1803.     if (name != 0) {
  1804.         size_t j, k;
  1805.  
  1806.         TRACE(("insert_per_major %ld %s\n", (long) count, name))
  1807.  
  1808.         for (j = 0; j < count; j++) {
  1809.             if (strcmp(my_mode_list[j], name) > 0)
  1810.                 break;
  1811.         }
  1812.         for (k = ++count; k != j; k--)
  1813.             my_mode_list[k] = my_mode_list[k-1];
  1814.         my_mode_list[j] = strmalloc(name);
  1815.     }
  1816.     return count;
  1817. }
  1818.  
  1819. /*
  1820.  * Remove 'name' from 'my_mode_list[]', which has 'count' entries.
  1821.  */
  1822. static size_t
  1823. remove_per_major(size_t count, const char *name)
  1824. {
  1825.     if (name != 0) {
  1826.         size_t j, k;
  1827.  
  1828.         for (j = 0; j < count; j++) {
  1829.             if (strcmp(my_mode_list[j], name) == 0) {
  1830.                 free(TYPECAST(char,my_mode_list[j]));
  1831.                 count--;
  1832.                 for (k = j; k <= count; k++)
  1833.                     my_mode_list[k] = my_mode_list[k+1];
  1834.                 break;
  1835.             }
  1836.         }
  1837.     }
  1838.     return count;
  1839. }
  1840.  
  1841. /*
  1842.  * Lookup a majormode's data area, given its short name, e.g., "c" vs "cmode".
  1843.  * We store the majormodes in an array to simplify name completion, though this
  1844.  * complicates definition and removal.
  1845.  */
  1846. static MAJORMODE *
  1847. lookup_mm_data(const char *name)
  1848. {
  1849.     size_t n;
  1850.     if (my_majormodes != 0) {
  1851.         for (n = 0; my_majormodes[n].name != 0; n++) {
  1852.             if (!strcmp(name, my_majormodes[n].name))
  1853.                 return my_majormodes[n].data;
  1854.         }
  1855.     }
  1856.     return 0;
  1857. }
  1858.  
  1859. /*
  1860.  * Lookup a majormode's data area, given its short name, e.g., "c" vs "cmode".
  1861.  * We store the majormodes in an array to simplify name completion, though this
  1862.  * complicates definition and removal.
  1863.  */
  1864. static MAJORMODE_LIST *
  1865. lookup_mm_list(const char *name)
  1866. {
  1867.     size_t n;
  1868.     if (my_majormodes != 0) {
  1869.         for (n = 0; my_majormodes[n].name != 0; n++) {
  1870.             if (!strcmp(name, my_majormodes[n].name))
  1871.                 return my_majormodes+n;
  1872.         }
  1873.     }
  1874.     return 0;
  1875. }
  1876.  
  1877. /* Check if a majormode is predefined.  There are some things we don't want to
  1878.  * do to them (such as remove them).
  1879.  */
  1880. static int predef_majormode(const char *name)
  1881. {
  1882.     size_t n;
  1883.     int status = FALSE;
  1884.  
  1885.     if (my_majormodes != 0) {
  1886.         for (n = 0; my_majormodes[n].name != 0; n++) {
  1887.             if (!strcmp(name, my_majormodes[n].name)) {
  1888.                 status = my_majormodes[n].init;
  1889.                 break;
  1890.             }
  1891.         }
  1892.     }
  1893.     return status;
  1894. }
  1895.  
  1896. static int
  1897. major_complete(int c, char *buf, unsigned *pos)
  1898. {
  1899.     return kbd_complete(FALSE, c, buf, pos, (const char *)&my_majormodes[0],
  1900.         sizeof(my_majormodes[0]));
  1901. }
  1902.  
  1903. static int
  1904. prompt_majormode(char **result, int defining)
  1905. {
  1906.     static TBUFF *cbuf;     /* buffer to receive mode name into */
  1907.     int status;
  1908.  
  1909.     /* prompt the user and get an answer */
  1910.     tb_scopy(&cbuf, "");
  1911.     if ((status = kbd_reply("majormode: ",
  1912.         &cbuf,
  1913.         eol_history, ' ',
  1914.         KBD_NORMAL,    /* FIXME: KBD_MAYBEC if !defining */
  1915.         (defining || clexec)
  1916.             ? no_completion
  1917.             : major_complete)) == TRUE) {
  1918.         /* check for legal name (alphanumeric) */
  1919.         if ((status = is_identifier(tb_values(cbuf))) != TRUE) {
  1920.             mlwarn("[Not an identifier: %s]", tb_values(cbuf));
  1921.             return status;
  1922.         }
  1923.         if ((status = is_varmode(tb_values(cbuf))) == TRUE) {
  1924.             *result = tb_values(cbuf);
  1925.             if (defining && lookup_mm_data(*result) != 0) {
  1926.                 TRACE(("Mode already exists\n"))
  1927.                 return SORTOFTRUE;
  1928.             } else if (!defining && lookup_mm_data(*result) == 0) {
  1929.                 TRACE(("Mode does not exist\n"))
  1930.                 return SORTOFTRUE;
  1931.             }
  1932.             return TRUE;
  1933.         }
  1934.     }
  1935.     if (status != FALSE)
  1936.         mlwarn("[Illegal name %s]", tb_values(cbuf));
  1937.     return status;
  1938. }
  1939.  
  1940. static int
  1941. submode_complete(int c, char *buf, unsigned *pos)
  1942. {
  1943.     return kbd_complete(FALSE, c, buf, pos, (const char *)&all_submodes[0],
  1944.         sizeof(all_submodes[0]));
  1945. }
  1946.  
  1947. static int
  1948. prompt_submode(char **result, int defining)
  1949. {
  1950.     static TBUFF *cbuf;     /* buffer to receive mode name into */
  1951.     register const char *rp;
  1952.     int status;
  1953.  
  1954.     /* prompt the user and get an answer */
  1955.     tb_scopy(&cbuf, "");
  1956.     if ((status = kbd_reply("submode: ",
  1957.         &cbuf,
  1958.         eol_history, '=',
  1959.         KBD_NORMAL,
  1960.         submode_complete)) == TRUE) {
  1961.         if ((status = ok_submode(tb_values(cbuf))) == TRUE) {
  1962.             *result = tb_values(cbuf);
  1963.             rp = !strncmp(*result, "no", 2) ? *result+2 : *result;
  1964.             if (defining && lookup_mm_data(rp) != 0) {
  1965.                 TRACE(("Mode already exists\n"))
  1966.                 return SORTOFTRUE;
  1967.             } else if (!defining && lookup_mm_data(rp) == 0) {
  1968.                 TRACE(("Mode does not exist\n"))
  1969.                 return SORTOFTRUE;
  1970.             }
  1971.             return TRUE;
  1972.         }
  1973.     }
  1974.     mlwarn("[Illegal name %s]", tb_values(cbuf));
  1975.     return status;
  1976. }
  1977.  
  1978. /*
  1979.  * Attach a buffer to the given majormode.  Adjust all of the non-local buffer
  1980.  * modes to point to the majormode's values where those in turn are local.
  1981.  */
  1982. static int
  1983. attach_mmode(BUFFER *bp, const char *name)
  1984. {
  1985.     int n;
  1986.  
  1987.     if (bp != 0) {
  1988.         if (bp->majr != 0
  1989.          && strcmp(bp->majr->name, name) != 0)
  1990.             (void) detach_mmode(bp, bp->majr->name);
  1991.  
  1992.         TRACE(("attach_mmode '%s' to '%s'\n", name, bp->b_bname))
  1993.         if ((bp->majr = lookup_mm_data(name)) != 0) {
  1994.             struct VAL *mm = bp->majr->mb.bv;
  1995.  
  1996.             /* adjust buffer modes */
  1997.             for (n = 0; n < MAX_B_VALUES; n++) {
  1998.                 if (!is_local_b_val(bp,n)
  1999.                  && is_local_val(mm,n)) {
  2000.                     make_global_val(bp->b_values.bv, mm, n);
  2001.                 }
  2002.             }
  2003.             return TRUE;
  2004.         }
  2005.         return (bp->majr != 0);
  2006.     }
  2007.  
  2008.     return FALSE;
  2009. }
  2010.  
  2011. /*
  2012.  * Detach a buffer from the given majormode.  Modify the buffer's minor modes
  2013.  * to point to global modes where they've been pointed to the majormode's data.
  2014.  */
  2015. static int
  2016. detach_mmode(BUFFER *bp, const char *name)
  2017. {
  2018.     size_t n;
  2019.     MAJORMODE *mp = 0;
  2020.  
  2021.     if (bp != 0
  2022.      && (mp = bp->majr) != 0
  2023.      && !strcmp(mp->name, name)) {
  2024.         TRACE(("detach_mmode '%s', given '%s'\n", name, mp->name))
  2025.         /* readjust the buffer's modes */
  2026.         for (n = 0; n < MAX_B_VALUES; n++) {
  2027.             if (!is_local_b_val(bp,n)
  2028.              && is_local_val(mp->mb.bv,n)) {
  2029.                 make_global_b_val(bp,n);
  2030.             }
  2031.         }
  2032.         relist_settings();
  2033.         bp->majr = 0;
  2034.         return TRUE;
  2035.     }
  2036.  
  2037.     return FALSE;
  2038. }
  2039.  
  2040. static int
  2041. enable_mmode(const char *name, int flag)
  2042. {
  2043.     MAJORMODE_LIST *ptr = lookup_mm_list(name);
  2044.     if (ptr != 0
  2045.      && ptr->flag != flag) {
  2046.         ptr->flag = flag;
  2047.         return TRUE;
  2048.     }
  2049.     return FALSE;
  2050. }
  2051.  
  2052. static int
  2053. free_majormode(const char *name)
  2054. {
  2055.     MAJORMODE *ptr = lookup_mm_data(name);
  2056.     size_t j, k;
  2057.     int n;
  2058.     char temp[NSTRING];
  2059.     BUFFER *bp;
  2060.  
  2061.     if (ptr != 0) {
  2062.         int init = TRUE;
  2063.         for (j = 0; my_majormodes[j].name != 0; j++) {
  2064.             if (my_majormodes[j].data == ptr) {
  2065.                 init = my_majormodes[j].init;
  2066.                 for_each_buffer(bp) {
  2067.                     if (detach_mmode(bp, my_majormodes[j].name)) {
  2068.                         set_winflags(TRUE, WFHARD|WFMODE);
  2069.                     }
  2070.                 }
  2071.                 free_local_vals(m_valnames, major_g_vals, ptr->mm.mv);
  2072.                 free_local_vals(b_valnames, global_b_values.bv, ptr->mb.bv);
  2073.                 for (k = 0; k < MAX_M_VALUES; k++) {
  2074.                     free(TYPECAST(char,my_majormodes[j].qual[k].name));
  2075.                     free(TYPECAST(char,my_majormodes[j].qual[k].shortname));
  2076.                 }
  2077.                 free(ptr->name);
  2078.                 free(ptr);
  2079.                 do {
  2080.                     my_majormodes[j] = my_majormodes[j+1];
  2081.                 } while (my_majormodes[j++].name != 0);
  2082.                 break;
  2083.             }
  2084.         }
  2085.         if (my_mode_list != all_modes && !init) {
  2086.             j = count_modes();
  2087.             j = remove_per_major(j, majorname(temp, name, FALSE));
  2088.             j = remove_per_major(j, majorname(temp, name, TRUE));
  2089.             for (n = 0; n < MAX_M_VALUES; n++) {
  2090.                 j = remove_per_major(j,
  2091.                     per_major(temp, name, n, TRUE));
  2092.                 j = remove_per_major(j,
  2093.                     per_major(temp, name, n, FALSE));
  2094.             }
  2095.         }
  2096.         if (major_valnames != 0) {
  2097.             for (n = 0; major_valnames[n].name != 0; n++) {
  2098.                 if (!strcmp(name, major_valnames[n].shortname)) {
  2099.                     free(TYPECAST(char,major_valnames[n].name));
  2100.                     free(TYPECAST(char,major_valnames[n].shortname));
  2101.                     while (major_valnames[n].name != 0) {
  2102.                         major_valnames[n] =
  2103.                         major_valnames[n+1];
  2104.                         n++;
  2105.                     }
  2106.                     break;
  2107.                 }
  2108.             }
  2109.         }
  2110.         return TRUE;
  2111.     }
  2112.     return FALSE;
  2113. }
  2114.  
  2115. static void
  2116. init_my_mode_list(void)
  2117. {
  2118.     if (my_mode_list == 0)
  2119.         my_mode_list = TYPECAST(const char *,all_modes);
  2120. }
  2121.  
  2122. static int
  2123. extend_mode_list(int increment)
  2124. {
  2125.     int j = count_modes();
  2126.     int k = increment + j + 1;
  2127.  
  2128.     TRACE(("extend_mode_list from %d by %d\n", j, increment))
  2129.  
  2130.     if (my_mode_list == all_modes) {
  2131.         my_mode_list = typeallocn(const char *, k);
  2132.         memcpy((char *)my_mode_list, all_modes, (j+1) * sizeof(*my_mode_list));
  2133.     } else {
  2134.         my_mode_list = typereallocn(const char *, my_mode_list, k);
  2135.     }
  2136.     return j;
  2137. }
  2138.  
  2139. static struct VAL *
  2140. extend_VAL_array(struct VAL *ptr, size_t item, size_t len)
  2141. {
  2142.     size_t j, k;
  2143.  
  2144.     TRACE(("extend_VAL_array %p item %ld of %ld\n", ptr, (long)item, (long)len))
  2145.  
  2146.     if (ptr == 0) {
  2147.         ptr = typeallocn(struct VAL, len + 1);
  2148.     } else {
  2149.         ptr = typereallocn(struct VAL, ptr, len + 1);
  2150.         for (j = k = 0; j < len; j++) {
  2151.             k = (j >= item) ? j+1 : j;
  2152.             ptr[k] = ptr[j];
  2153.             make_local_val(ptr, k);
  2154.         }
  2155.     }
  2156.     make_local_val(ptr, item);
  2157.     make_local_val(ptr, len);
  2158.     ptr[item].v.i = FALSE;
  2159.     return ptr;
  2160. }
  2161.  
  2162. static void
  2163. set_qualifier(const struct VALNAMES *names, struct VAL *values, const char *s)
  2164. {
  2165.     switch (names->type) {
  2166.     case VALTYPE_STRING:
  2167.         if (values->v.p)
  2168.             free(values->v.p);
  2169.         values->v.p = strmalloc(s);
  2170.         break;
  2171.     case VALTYPE_REGEX:
  2172.         free_regexval(values->v.r);
  2173.         values->v.r = new_regexval(s, TRUE);
  2174.         break;
  2175.     }
  2176.     make_local_val(values, 0);
  2177. }
  2178.  
  2179. static void
  2180. reset_qualifier(const struct VALNAMES *names, struct VAL *values)
  2181. {
  2182.     set_qualifier(names, values, "");
  2183. }
  2184.  
  2185. /*
  2186.  * Buffer-animation for [Major Modes]
  2187.  */
  2188. #if OPT_UPBUFF
  2189. static int
  2190. show_majormodes(BUFFER *bp)
  2191. {
  2192.     b_clr_obsolete(bp);
  2193.     return list_majormodes(FALSE, 1);
  2194. }
  2195.  
  2196. static void
  2197. relist_majormodes(void)
  2198. {
  2199.     update_scratch(MAJORMODES_BufName, show_majormodes);
  2200. }
  2201. #endif    /* OPT_UPBUFF */
  2202.  
  2203. /* list the current modes into the current buffer */
  2204. /* ARGSUSED */
  2205. static void
  2206. makemajorlist(int local, void *ptr GCC_UNUSED)
  2207. {
  2208.     int j;
  2209.     int nflag;
  2210.     MAJORMODE *data;
  2211.  
  2212.     if (my_majormodes != 0) {
  2213.         for (j = 0; my_majormodes[j].name != 0; j++) {
  2214.             if (local)
  2215.                 TheMajor = my_majormodes[j].name;
  2216.             nflag = 0;
  2217.             data = my_majormodes[j].data;
  2218.             bprintf("--- \"%s\" majormode settings %*P\n",
  2219.                 my_majormodes[j].name,
  2220.                 term.t_ncol-1, '-');
  2221.             nflag = listvalueset("Qualifier", FALSE, TRUE,
  2222.                 m_valnames,
  2223.                 data->mm.mv,
  2224.                 data->mm.mv);
  2225.             nflag = listvalueset("Buffer",    nflag, TRUE,
  2226.                 b_valnames,
  2227.                 data->mb.bv,
  2228.                 global_b_values.bv);
  2229.             if (my_majormodes[j+1].data)
  2230.                 bputc('\n');
  2231.         }
  2232.     }
  2233.     TheMajor = 0;
  2234. }
  2235.  
  2236. /* ARGSUSED */
  2237. int
  2238. list_majormodes(int f, int n GCC_UNUSED)
  2239. {
  2240.     register WINDOW *wp = curwp;
  2241.     register int s;
  2242.  
  2243.     s = liststuff(MAJORMODES_BufName, FALSE, makemajorlist,f,(void *)wp);
  2244.     /* back to the buffer whose modes we just listed */
  2245.     if (swbuffer(wp->w_bufp))
  2246.         curwp = wp;
  2247.  
  2248.     return s;
  2249. }
  2250.  
  2251. int
  2252. alloc_mode(const char *name, int predef)
  2253. {
  2254.     size_t j, k;
  2255.     int n;
  2256.     char temp[NSTRING];
  2257.  
  2258.     if (major_valnames == 0) {
  2259.         major_valnames = typecallocn(struct VALNAMES, 2);
  2260.         j = 0;
  2261.         k = 1;
  2262.     } else {
  2263.         k = count_majormodes();
  2264.         major_valnames = typereallocn(struct VALNAMES, major_valnames, k+2);
  2265.         for (j = k++; j != 0; j--) {
  2266.             major_valnames[j] = major_valnames[j-1];
  2267.             if (strcmp(major_valnames[j-1].shortname, name) < 0) {
  2268.                 break;
  2269.             }
  2270.         }
  2271.     }
  2272.  
  2273.     (void) majorname(temp, name, TRUE);
  2274.     major_valnames[j].name        = strmalloc(temp);
  2275.     major_valnames[j].shortname   = strmalloc(name);
  2276.     major_valnames[j].type        = VALTYPE_MAJOR;
  2277.     major_valnames[j].side_effect = chgd_major_w;
  2278.  
  2279.     memset(major_valnames+k, 0, sizeof(*major_valnames));
  2280.  
  2281.     /* build arrays needed for 'find_mode()' bookkeeping */
  2282.     major_g_vals = extend_VAL_array(major_g_vals, j, k);
  2283.     major_l_vals = extend_VAL_array(major_l_vals, j, k);
  2284.  
  2285.     if (my_majormodes == 0) {
  2286.         my_majormodes = typecallocn(MAJORMODE_LIST, 2);
  2287.         j = 0;
  2288.         k = 1;
  2289.     } else {
  2290.         k = count_majormodes();
  2291.         my_majormodes = typereallocn(MAJORMODE_LIST, my_majormodes, k+2);
  2292.         for (j = k++; j != 0; j--) {
  2293.             my_majormodes[j] = my_majormodes[j-1];
  2294.             if (strcmp(my_majormodes[j-1].name, name) < 0) {
  2295.                 break;
  2296.             }
  2297.         }
  2298.     }
  2299.  
  2300.     my_majormodes[j].data = typecalloc(MAJORMODE);
  2301.     my_majormodes[j].name = my_majormodes[j].data->name = strmalloc(name);
  2302.     my_majormodes[j].init = predef;
  2303.     my_majormodes[j].flag = TRUE;
  2304.     memset(my_majormodes+k, 0, sizeof(*my_majormodes));
  2305.  
  2306.     for (k = 0; k < MAX_B_VALUES; k++) {
  2307.         make_global_val(my_majormodes[j].data->mb.bv, global_b_values.bv, k);
  2308.     }
  2309.  
  2310.     /* copy array to get types, then overwrite the name-pointers */
  2311.     memcpy(my_majormodes[j].qual, m_valnames, sizeof(m_valnames));
  2312.     for (k = 0; k < MAX_M_VALUES; k++) {
  2313.         reset_qualifier(m_valnames+k, my_majormodes[j].data->mm.mv+k);
  2314.         my_majormodes[j].qual[k].name =
  2315.                 strmalloc(per_major(temp, name, k, TRUE));
  2316.         my_majormodes[j].qual[k].shortname =
  2317.                 strmalloc(per_major(temp, name, k, FALSE));
  2318.     }
  2319.  
  2320.     /*
  2321.      * Create the majormode-specific names.  If this is predefined, we
  2322.      * already had mktbls do this.
  2323.      */
  2324.     if (!predef) {
  2325.         j = extend_mode_list((MAX_M_VALUES + 2) * 2);
  2326.         j = insert_per_major(j, majorname(temp, name, FALSE));
  2327.         j = insert_per_major(j, majorname(temp, name, TRUE));
  2328.         for (n = 0; n < MAX_M_VALUES; n++) {
  2329.             j = insert_per_major(j, per_major(temp, name, n, TRUE));
  2330.             j = insert_per_major(j, per_major(temp, name, n, FALSE));
  2331.         }
  2332.     }
  2333.  
  2334.     return TRUE;
  2335. }
  2336.  
  2337. /* ARGSUSED */
  2338. int
  2339. define_mode(int f GCC_UNUSED, int n GCC_UNUSED)
  2340. {
  2341.     char *name;
  2342.     int status;
  2343.  
  2344.     if ((status = prompt_majormode(&name, TRUE)) == TRUE) {
  2345.         TRACE(("define majormode:%s\n", name))
  2346.         status = alloc_mode(name, FALSE);
  2347.         relist_settings();
  2348.         relist_majormodes();
  2349.     } else if (status == SORTOFTRUE) {
  2350.         status = TRUE;    /* don't complain if it's already true */
  2351.     }
  2352.     return status;
  2353. }
  2354.  
  2355. static int
  2356. do_a_submode(int defining)
  2357. {
  2358.     char *name;
  2359.     char *subname;
  2360.     int status;
  2361.     MAJORMODE *ptr;
  2362.     VALARGS args;
  2363.     int j, k;
  2364.     int qualifier = FALSE;
  2365.     char temp[NSTRING];
  2366.     char *rp;
  2367.  
  2368.     if ((status = prompt_majormode(&name, FALSE)) != TRUE)
  2369.         return status;
  2370.  
  2371.     if ((status = prompt_submode(&subname, TRUE)) != TRUE)
  2372.         return status;
  2373.  
  2374.     ptr = lookup_mm_data(name);
  2375.     rp = !strncmp(subname, "no", 2) ? subname+2 : subname;
  2376.     if ((j = lookup_valnames(rp, m_valnames)) >= 0) {
  2377.         qualifier   = TRUE;
  2378.         args.names  = m_valnames;
  2379.         args.global = ptr->mm.mv;
  2380.         args.local  = ptr->mm.mv;
  2381.     } else if ((j = lookup_valnames(rp, b_valnames)) >= 0) {
  2382.         args.names  = b_valnames;
  2383.         args.global = defining ? ptr->mb.bv :global_b_values.bv;
  2384.         args.local  = ptr->mb.bv;
  2385.     } else {
  2386.         mlwarn("[BUG: no such submode %s]", rp);
  2387.         return FALSE;
  2388.     }
  2389.  
  2390.     args.names  += j;
  2391.     args.global += j;
  2392.     args.local  += j;
  2393.  
  2394.     /*
  2395.      * We store submodes in the majormode as local values.
  2396.      */
  2397.     status = adjvalueset(subname, defining, FALSE, &args);
  2398.  
  2399.     /*
  2400.      * Check if we deleted one of the qualifiers, since there's no global
  2401.      * value to inherit back to, we'll have to ensure there's valid data.
  2402.      */
  2403.     if (status == TRUE
  2404.      && qualifier
  2405.      && !defining) {
  2406.         reset_qualifier(args.names, args.global);
  2407.     }
  2408.  
  2409.     if (status == TRUE
  2410.      && !qualifier) {
  2411.         if (defining && found_per_submode(name, j)) {
  2412.             TRACE(("submode names for %d present\n", j))
  2413.         } else if (defining) {
  2414.             TRACE(("construct submode names for %d\n", j))
  2415.             k = extend_mode_list(2);
  2416.             k = insert_per_major(k,
  2417.                 per_submode(temp, name, j, TRUE));
  2418.             k = insert_per_major(k,
  2419.                 per_submode(temp, name, j, FALSE));
  2420.         } else {
  2421.             TRACE(("destroy submode names for %d\n", j))
  2422.             k = count_modes();
  2423.             k = remove_per_major(k,
  2424.                 per_submode(temp, name, j, TRUE));
  2425.             k = remove_per_major(k,
  2426.                 per_submode(temp, name, j, FALSE));
  2427.         }
  2428.     }
  2429.  
  2430.     /* FIXME: remember to adjust all buffers that used this mode, in
  2431.      * case we make a minor mode part-of or removed from the major mode.
  2432.      */
  2433.     relist_settings();
  2434.     relist_majormodes();
  2435.     return status;
  2436. }
  2437.  
  2438. /* ARGSUSED */
  2439. int
  2440. define_submode(int f GCC_UNUSED, int n GCC_UNUSED)
  2441. {
  2442.     return do_a_submode(TRUE);
  2443. }
  2444.  
  2445. /* ARGSUSED */
  2446. int
  2447. remove_submode(int f GCC_UNUSED, int n GCC_UNUSED)
  2448. {
  2449.     return do_a_submode(FALSE);
  2450. }
  2451.  
  2452. /* ARGSUSED */
  2453. int
  2454. remove_mode(int f GCC_UNUSED, int n GCC_UNUSED)
  2455. {
  2456.     char *name;
  2457.     int status;
  2458.  
  2459.     if ((status = prompt_majormode(&name, FALSE)) == TRUE) {
  2460.         if ((status = !predef_majormode(name)) == TRUE) {
  2461.             TRACE(("remove majormode:%s\n", name))
  2462.             free_majormode(name);
  2463.             relist_settings();
  2464.             relist_majormodes();
  2465.         } else {
  2466.             mlwarn("[This is a predefined mode: %s]", name);
  2467.         }
  2468.     } else if (status == SORTOFTRUE) {
  2469.         status = TRUE;
  2470.     }
  2471.     return status;
  2472. }
  2473.  
  2474. /*
  2475.  * Returns the regular expression for the given indices, checking that the
  2476.  * pattern is non-null.
  2477.  */
  2478. static regexp *
  2479. get_mm_rexp(int n, int m)
  2480. {
  2481.     struct VAL *mv = my_majormodes[n].data->mm.mv;
  2482.  
  2483.     if (mv[m].vp->r != 0
  2484.      && mv[m].vp->r->pat != 0
  2485.      && mv[m].vp->r->pat[0] != 0
  2486.      && mv[m].vp->r->reg != 0) {
  2487.         TRACE(("get_mm_rexp(%s) %s\n",
  2488.             my_majormodes[n].name,
  2489.             mv[m].vp->r->pat))
  2490.         return mv[m].vp->r->reg;
  2491.     }
  2492.     return 0;
  2493. }
  2494.  
  2495. /*
  2496.  * Use a regular expression (normally a suffix, such as ".c") to match the
  2497.  * buffer's filename.  If found, set the first matching majormode.
  2498.  */
  2499. void
  2500. setm_by_suffix(register BUFFER *bp)
  2501. {
  2502.     if (my_majormodes != 0) {
  2503.         size_t n = 0;
  2504.         int savecase = ignorecase;
  2505. #if OPT_CASELESS
  2506.         ignorecase = TRUE;
  2507. #else
  2508.         ignorecase = FALSE;
  2509. #endif
  2510.  
  2511.         for (n = 0; my_majormodes[n].name != 0; n++) {
  2512.             if (my_majormodes[n].flag) {
  2513.                 regexp *exp = get_mm_rexp(n, MVAL_SUFFIXES);
  2514.                 if (exp != 0
  2515.                  && regexec(exp, bp->b_fname, (char *)0, 0, -1)) {
  2516.                     attach_mmode(bp, my_majormodes[n].name);
  2517.                     break;
  2518.                 }
  2519.             }
  2520.         }
  2521.         ignorecase = savecase;
  2522.     }
  2523. }
  2524.  
  2525. static LINE *
  2526. get_preamble(register BUFFER *bp)
  2527. {
  2528.     if (!is_empty_buf(bp)) {
  2529.         LINE *lp = lforw(buf_head(bp));
  2530.         if (lisreal(lp))
  2531.             return lp;
  2532.     }
  2533.     return 0;
  2534. }
  2535.  
  2536. /*
  2537.  * Match the first line of the buffer against a regular expression, setting
  2538.  * the first matching majormode, if any.
  2539.  */
  2540. void
  2541. setm_by_preamble(register BUFFER *bp)
  2542. {
  2543.     LINE *lp = get_preamble(bp);
  2544.  
  2545.     if (lp != 0
  2546.      && my_majormodes != 0) {
  2547.         size_t n = 0;
  2548.         int savecase = ignorecase;
  2549. #if OPT_CASELESS
  2550.         ignorecase = TRUE;
  2551. #else
  2552.         ignorecase = FALSE;
  2553. #endif
  2554.  
  2555.         for (n = 0; my_majormodes[n].name != 0; n++) {
  2556.             if (my_majormodes[n].flag) {
  2557.                 regexp *exp = get_mm_rexp(n, MVAL_PREAMBLE);
  2558.                 if (exp != 0
  2559.                  && lregexec(exp, lp, 0, llength(lp))) {
  2560.                     attach_mmode(bp, my_majormodes[n].name);
  2561.                     break;
  2562.                  }
  2563.             }
  2564.         }
  2565.         ignorecase = savecase;
  2566.     }
  2567. }
  2568.  
  2569. void
  2570. set_submode_val(const char *name, int n, int value)
  2571. {
  2572.     MAJORMODE *p;
  2573.     TRACE(("set_majormode_val(%s, %d, %d)\n", name, n, value))
  2574.     if ((p = lookup_mm_data(name)) != 0) {
  2575.         p->mb.bv[n].v.i = value;
  2576.         make_local_val(p->mb.bv, n);
  2577.     }
  2578. }
  2579.  
  2580. void
  2581. set_majormode_rexp(const char *name, int n, const char *r)
  2582. {
  2583.     MAJORMODE *p;
  2584.     TRACE(("set_majormode_rexp(%s, %d, %s)\n", name, n, r))
  2585.     if ((p = lookup_mm_data(name)) != 0)
  2586.         set_qualifier(m_valnames+n, p->mm.mv + n, r);
  2587. }
  2588. #endif /* OPT_MAJORMODE */
  2589.  
  2590. /*--------------------------------------------------------------------------*/
  2591.  
  2592. #if NO_LEAKS
  2593. void
  2594. mode_leaks(void)
  2595. {
  2596. #if OPT_ENUM_MODES && OPT_COLOR
  2597.     FreeAndNull(my_colors);
  2598.     FreeAndNull(my_hilite);
  2599. #endif
  2600.  
  2601. #if OPT_EVAL || OPT_MAJORMODE
  2602.     FreeAndNull(my_varmodes);
  2603. #endif
  2604. #if OPT_MAJORMODE
  2605.     while (my_majormodes != 0 && my_majormodes->name != 0) {
  2606.         char temp[NSTRING];
  2607.         free_majormode(strcpy(temp, my_majormodes->name));
  2608.     }
  2609.     FreeAndNull(my_majormodes);
  2610.  
  2611.     FreeAndNull(major_g_vals);
  2612.     FreeAndNull(major_l_vals);
  2613.     FreeAndNull(my_mode_list);
  2614.     FreeAndNull(major_valnames);
  2615. #endif
  2616. }
  2617. #endif /* NO_LEAKS */
  2618.