home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / xvi / part09 < prev    next >
Encoding:
Text File  |  1992-10-22  |  55.2 KB  |  2,270 lines

  1. Newsgroups: comp.sources.misc
  2. From: jmd@cyclone.bt.co.uk (John Downey)
  3. Subject:  v33i018:  xvi - portable multi-window vi-like editor, Part09/18
  4. Message-ID: <1992Oct23.181408.474@sparky.imd.sterling.com>
  5. X-Md4-Signature: 926bf559148a32b7a7be6e4b10deec51
  6. Date: Fri, 23 Oct 1992 18:14:08 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: jmd@cyclone.bt.co.uk (John Downey)
  10. Posting-number: Volume 33, Issue 18
  11. Archive-name: xvi/part09
  12. Environment: Unix, MS-DOS, OS/2, QNX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  xvi/src/cmdline.c xvi/src/param.c xvi/src/regexp.h
  19. # Wrapped by kent@sparky on Thu Oct 22 09:03:42 1992
  20. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  21. echo If this archive is complete, you will see the following message:
  22. echo '          "shar: End of archive 9 (of 18)."'
  23. if test -f 'xvi/src/cmdline.c' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'xvi/src/cmdline.c'\"
  25. else
  26.   echo shar: Extracting \"'xvi/src/cmdline.c'\" \(27270 characters\)
  27.   sed "s/^X//" >'xvi/src/cmdline.c' <<'END_OF_FILE'
  28. X/* Copyright (c) 1990,1991,1992 Chris and John Downey */
  29. X#ifndef lint
  30. Xstatic char *sccsid = "@(#)cmdline.c    2.2 (Chris & John Downey) 8/6/92";
  31. X#endif
  32. X
  33. X/***
  34. X
  35. X* program name:
  36. X    xvi
  37. X* function:
  38. X    PD version of UNIX "vi" editor, with extensions.
  39. X* module name:
  40. X    cmdline.c
  41. X* module function:
  42. X    Command-line handling (i.e. :/? commands) - most
  43. X    of the actual command functions are in ex_cmds.c.
  44. X* history:
  45. X    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  46. X    Originally by Tim Thompson (twitch!tjt)
  47. X    Extensive modifications by Tony Andrews    (onecom!wldrdg!tony)
  48. X    Heavily modified by Chris & John Downey
  49. X
  50. X***/
  51. X
  52. X#include "xvi.h"
  53. X
  54. X#ifdef    MEGAMAX
  55. Xoverlay "cmdline"
  56. X#endif
  57. X
  58. X/*
  59. X * The next two variables contain the bounds of any range
  60. X * given in a command. If no range was given, both will be NULL.
  61. X * If only a single line was given, u_line will be NULL.
  62. X * The a_line variable is used for those commands which take
  63. X * a third line specifier after the command, e.g. "move", "copy".
  64. X */
  65. Xstatic    Line    *l_line, *u_line;
  66. Xstatic    Line    *a_line;
  67. X
  68. X/*
  69. X * Definitions for all ex commands.
  70. X */
  71. X
  72. X#define    EX_ENOTFOUND    -1        /* command not found */
  73. X#define    EX_EAMBIGUOUS    -2        /* could be more than one */
  74. X#define    EX_ECANTFORCE    -3        /* ! given where not appropriate */
  75. X#define    EX_EBADARGS    -4        /* inappropriate args given */
  76. X
  77. X#define    EX_NOCMD    1
  78. X#define    EX_SHCMD    2
  79. X#define    EX_UNUSED    3    /* unused */
  80. X#define    EX_AMPERSAND    4
  81. X#define    EX_EXBUFFER    5
  82. X#define    EX_LSHIFT    6
  83. X#define    EX_EQUALS    7
  84. X#define    EX_RSHIFT    8
  85. X#define    EX_COMMENT    9
  86. X#define    EX_ABBREVIATE    10
  87. X#define    EX_APPEND    11
  88. X#define    EX_ARGS        12
  89. X#define    EX_BUFFER    13
  90. X#define    EX_CHDIR    14
  91. X#define    EX_CHANGE    15
  92. X#define    EX_CLOSE    16
  93. X#define    EX_COMPARE    17
  94. X#define    EX_COPY        18
  95. X#define    EX_DELETE    19
  96. X#define    EX_ECHO        20
  97. X#define    EX_EDIT        21
  98. X#define    EX_EX        22
  99. X#define    EX_FILE        23
  100. X#define    EX_GLOBAL    24
  101. X#define    EX_HELP        25
  102. X#define    EX_INSERT    26
  103. X#define    EX_JOIN        27
  104. X#define    EX_K        28
  105. X#define    EX_LIST        29
  106. X#define    EX_MAP        30
  107. X#define    EX_MARK        31
  108. X#define    EX_MOVE        32
  109. X#define    EX_NEXT        33
  110. X#define    EX_NUMBER    34
  111. X#define    EX_OPEN        35
  112. X#define    EX_PRESERVE    36
  113. X#define    EX_PRINT    37
  114. X#define    EX_PUT        38
  115. X#define    EX_QUIT        39
  116. X#define    EX_READ        40
  117. X#define    EX_RECOVER    41
  118. X#define    EX_REWIND    42
  119. X#define    EX_SET        43
  120. X#define    EX_SHELL    44
  121. X#define    EX_SOURCE    45
  122. X#define    EX_SPLIT    46
  123. X#define    EX_SUSPEND    47
  124. X#define    EX_SUBSTITUTE    48
  125. X#define    EX_TAG        49
  126. X#define    EX_UNABBREV    50
  127. X#define    EX_UNDO        51
  128. X#define    EX_UNMAP    52
  129. X#define    EX_V        53
  130. X#define    EX_VERSION    54
  131. X#define    EX_VISUAL    55
  132. X#define    EX_WN        56
  133. X#define    EX_WQ        57
  134. X#define    EX_WRITE    58
  135. X#define    EX_XIT        59
  136. X#define    EX_YANK        60
  137. X#define    EX_Z        61
  138. X#define    EX_GOTO        62
  139. X#define    EX_TILDE    63
  140. X
  141. X/*
  142. X * Table of all ex commands, and whether they take an '!'.
  143. X *
  144. X * Note that this table is in strict order, sorted on
  145. X * the ASCII value of the first character of the command.
  146. X *
  147. X * The priority field is necessary to resolve clashes in
  148. X * the first one or two characters; so each group of commands
  149. X * beginning with the same letter should have at least one
  150. X * priority 1, so that there is a sensible default.
  151. X *
  152. X * Commands with argument type ec_rest need no delimiters;
  153. X * they need only be matched. This is really only used for
  154. X * single-character commands like !, " and &.
  155. X */
  156. Xstatic    struct    ecmd    {
  157. X    char    *ec_name;
  158. X    short    ec_command;
  159. X    short    ec_priority;
  160. X    unsigned    ec_flags;
  161. X    /*
  162. X     * Flags: EXCLAM means can use !, FILEXP means do filename
  163. X     * expansion, INTEXP means do % and # expansion. EXPALL means
  164. X     * do INTEXP and FILEXP (they are done in that order).
  165. X     *
  166. X     * EC_RANGE0 means that the range specifier (if any)
  167. X     * may include line 0.
  168. X     */
  169. X#   define    EC_EXCLAM    0x1
  170. X#   define    EC_FILEXP    0x2
  171. X#   define    EC_INTEXP    0x4
  172. X#   define    EC_EXPALL    EC_FILEXP|EC_INTEXP
  173. X#   define    EC_RANGE0    0x8
  174. X
  175. X    enum {
  176. X    ec_none,        /* no arguments after command */
  177. X    ec_strings,        /* whitespace-separated strings */
  178. X    ec_1string,        /* like ec_strings but only one */
  179. X    ec_line,        /* line number or target argument */
  180. X    ec_rest,        /* rest of line passed entirely */
  181. X    ec_nonalnum,        /* non-alphanumeric delimiter */
  182. X    ec_1lower        /* single lower-case letter */
  183. X    }    ec_arg_type;
  184. X} cmdtable[] = {
  185. X/*  name        command         priority    exclam    */
  186. X
  187. X    /*
  188. X     * The zero-length string is used for the :linenumber command.
  189. X     */
  190. X    "",            EX_NOCMD,        1,    EC_RANGE0,        ec_none,
  191. X    "!",        EX_SHCMD,        0,    EC_INTEXP,        ec_rest,
  192. X
  193. X    "#",        EX_NUMBER,        0,    0,            ec_none,
  194. X    "&",        EX_AMPERSAND,   0,    0,            ec_rest,
  195. X    "*",        EX_EXBUFFER,    0,    0,            ec_rest,
  196. X    "<",        EX_LSHIFT,        0,    0,            ec_none,
  197. X    "=",        EX_EQUALS,        0,    0,            ec_none,
  198. X    ">",        EX_RSHIFT,        0,    0,            ec_none,
  199. X    "@",        EX_EXBUFFER,    0,    0,            ec_rest,
  200. X    "\"",        EX_COMMENT,        0,    0,            ec_rest,
  201. X
  202. X    "abbreviate",   EX_ABBREVIATE,  0,    0,            ec_strings,
  203. X    "append",        EX_APPEND,        1,    0,            ec_none,
  204. X    "args",        EX_ARGS,        0,    0,            ec_none,
  205. X
  206. X    "buffer",        EX_BUFFER,        0,    EC_EXPALL,        ec_1string,
  207. X
  208. X    "cd",        EX_CHDIR,        1,    EC_EXPALL,        ec_1string,
  209. X    "change",        EX_CHANGE,        2,    0,            ec_none,
  210. X    "chdir",        EX_CHDIR,        1,    EC_EXPALL,        ec_1string,
  211. X    "close",        EX_CLOSE,        1,    EC_EXCLAM,        ec_none,
  212. X    "compare",        EX_COMPARE,        0,    0,            ec_none,
  213. X    "copy",        EX_COPY,        1,    0,            ec_line,
  214. X
  215. X    "delete",        EX_DELETE,        0,    0,            ec_none,
  216. X
  217. X    "echo",        EX_ECHO,        0,    EC_INTEXP,        ec_strings,
  218. X    "edit",        EX_EDIT,        1,    EC_EXCLAM|EC_EXPALL,    ec_1string,
  219. X    "ex",        EX_EX,        0,    EC_EXPALL,        ec_1string,
  220. X
  221. X    "file",        EX_FILE,        0,    EC_EXPALL,        ec_1string,
  222. X
  223. X    "global",        EX_GLOBAL,        0,    EC_EXCLAM,        ec_nonalnum,
  224. X
  225. X    "help",        EX_HELP,        0,    0,            ec_none,
  226. X
  227. X    "insert",        EX_INSERT,        0,    0,            ec_none,
  228. X
  229. X    "join",        EX_JOIN,        0,    0,            ec_none,
  230. X
  231. X    "k",        EX_K,        0,    0,            ec_1lower,
  232. X
  233. X    "list",        EX_LIST,        0,    0,            ec_none,
  234. X
  235. X    "map",        EX_MAP,        0,    EC_EXCLAM,        ec_strings,
  236. X    "mark",        EX_MARK,        0,    0,            ec_1lower,
  237. X    "move",        EX_MOVE,        1,    0,            ec_line,
  238. X
  239. X    "next",        EX_NEXT,        1,    EC_EXCLAM|EC_EXPALL,    ec_strings,
  240. X    "number",        EX_NUMBER,        0,    0,            ec_none,
  241. X
  242. X    "open",        EX_OPEN,        0,    0,            ec_none,
  243. X
  244. X    "preserve",        EX_PRESERVE,    0,    0,            ec_none,
  245. X    "print",        EX_PRINT,        1,    0,            ec_none,
  246. X    "put",        EX_PUT,        0,    EC_RANGE0,        ec_none,
  247. X
  248. X    "quit",        EX_QUIT,        0,    EC_EXCLAM,        ec_none,
  249. X
  250. X    "read",        EX_READ,        1,    EC_EXPALL|EC_RANGE0,    ec_1string,
  251. X    "recover",        EX_RECOVER,        0,    0,            ec_none,
  252. X    "rewind",        EX_REWIND,        0,    EC_EXCLAM,        ec_none,
  253. X
  254. X    "set",        EX_SET,        0,    0,            ec_strings,
  255. X    "shell",        EX_SHELL,        0,    0,            ec_none,
  256. X    "source",        EX_SOURCE,        0,    EC_EXPALL,        ec_1string,
  257. X    "split",        EX_SPLIT,        0,    0,            ec_none,
  258. X    "stop",        EX_SUSPEND,        0,    0,            ec_none,
  259. X    "substitute",   EX_SUBSTITUTE,  1,    0,            ec_nonalnum,
  260. X    "suspend",        EX_SUSPEND,        0,    0,            ec_none,
  261. X
  262. X    "t",        EX_COPY,        1,    0,            ec_line,
  263. X    "tag",        EX_TAG,        0,    EC_EXCLAM,        ec_1string,
  264. X
  265. X    "unabbreviate", EX_UNABBREV,    0,    0,            ec_strings,
  266. X    "undo",        EX_UNDO,        1,    0,            ec_none,
  267. X    "unmap",        EX_UNMAP,        0,    EC_EXCLAM,        ec_strings,
  268. X
  269. X    "v",        EX_V,        1,    0,            ec_nonalnum,
  270. X    "version",        EX_VERSION,        0,    0,            ec_none,
  271. X    "visual",        EX_VISUAL,        0,    EC_EXCLAM|EC_EXPALL,    ec_1string,
  272. X
  273. X    "wn",        EX_WN,        0,    EC_EXCLAM,        ec_none,
  274. X    "wq",        EX_WQ,        0,    EC_EXCLAM|EC_EXPALL,    ec_1string,
  275. X    "write",        EX_WRITE,        1,    EC_EXCLAM|EC_EXPALL,    ec_1string,
  276. X
  277. X    "xit",        EX_XIT,        0,    0,            ec_none,
  278. X
  279. X    "yank",        EX_YANK,        0,    0,            ec_none,
  280. X
  281. X    "z",        EX_Z,        0,    0,            ec_none,
  282. X
  283. X    "|",        EX_GOTO,        0,    0,            ec_none,
  284. X    "~",        EX_TILDE,        0,    0,            ec_rest,
  285. X
  286. X    NULL,        0,            0,    0,            ec_none,
  287. X};
  288. X
  289. X/*
  290. X * Internal routine declarations.
  291. X */
  292. Xstatic    int    decode_command P((char **, bool_t *, struct ecmd **));
  293. Xstatic    bool_t    get_line P((char **, Line **));
  294. Xstatic    bool_t    get_range P((char **));
  295. Xstatic    void    badcmd P((bool_t, char *));
  296. Xstatic    char    *show_line P((void));
  297. Xstatic    char    *expand_percents P((char *));
  298. X
  299. X/*
  300. X * These are used for display mode.
  301. X */
  302. Xstatic    Line    *curline;
  303. Xstatic    Line    *lastline;
  304. Xstatic    bool_t    do_line_numbers;
  305. X
  306. X/*
  307. X * Macro to skip over whitespace during command line interpretation.
  308. X */
  309. X#define skipblanks(p)    { while (*(p) != '\0' && is_space(*(p))) (p)++; }
  310. X
  311. X/*
  312. X * do_colon() - process a ':' command.
  313. X *
  314. X * The cmdline argument points to a complete command line to be processed
  315. X * (this does not include the ':' itself).
  316. X */
  317. Xvoid
  318. Xdo_colon(cmdline, interactive)
  319. Xchar    *cmdline;            /* optional command string */
  320. Xbool_t    interactive;            /* true if reading from tty */
  321. X{
  322. X    char    *arg;            /* ptr to string arg(s) */
  323. X    int        argc = 0;        /* arg count for ec_strings */
  324. X    char    **argv = NULL;        /* arg vector for ec_strings */
  325. X    bool_t    exclam;            /* true if ! was given */
  326. X    int        command;        /* which command it is */
  327. X    struct ecmd    *ecp;            /* ptr to command entry */
  328. X    unsigned    savecho;        /* previous value of echo */
  329. X
  330. X    /*
  331. X     * Clear the range variables.
  332. X     */
  333. X    l_line = NULL;
  334. X    u_line = NULL;
  335. X
  336. X    /*
  337. X     * Parse a range, if present (and update the cmdline pointer).
  338. X     */
  339. X    if (!get_range(&cmdline)) {
  340. X    return;
  341. X    }
  342. X
  343. X    /*
  344. X     * Decode the command.
  345. X     */
  346. X    skipblanks(cmdline);
  347. X    command = decode_command(&cmdline, &exclam, &ecp);
  348. X
  349. X    if (command > 0) {
  350. X    /*
  351. X     * Check that the range specified,
  352. X     * if any, is legal for the command.
  353. X     */
  354. X    if (!(ecp->ec_flags & EC_RANGE0)) {
  355. X        if (l_line == curbuf->b_line0 || u_line == curbuf->b_line0) {
  356. X        show_error(curwin,
  357. X            "Specification of line 0 not allowed");
  358. X        return;
  359. X        }
  360. X    }
  361. X
  362. X    switch (ecp->ec_arg_type) {
  363. X    case ec_none:
  364. X        if (*cmdline != '\0' &&
  365. X            (*cmdline != '!' || !(ecp->ec_flags & EC_EXCLAM))) {
  366. X        command = EX_EBADARGS;
  367. X        }
  368. X        break;
  369. X
  370. X    case ec_line:
  371. X        a_line = NULL;
  372. X        skipblanks(cmdline);
  373. X        if (!get_line(&cmdline, &a_line) || a_line == NULL) {
  374. X        command = EX_EBADARGS;
  375. X        }
  376. X        break;
  377. X
  378. X    case ec_1lower:
  379. X        /*
  380. X         * One lower-case letter.
  381. X         */
  382. X        skipblanks(cmdline);
  383. X        if (!is_lower(cmdline[0]) || cmdline[1] != '\0') {
  384. X        command = EX_EBADARGS;
  385. X        } else {
  386. X        arg = cmdline;
  387. X        }
  388. X        break;
  389. X
  390. X    case ec_nonalnum:
  391. X    case ec_rest:
  392. X    case ec_strings:
  393. X    case ec_1string:
  394. X        arg = cmdline;
  395. X        if (ecp->ec_arg_type == ec_strings ||
  396. X                    ecp->ec_arg_type == ec_1string) {
  397. X        if (*arg == '\0') {
  398. X            /*
  399. X             * No args.
  400. X             */
  401. X            arg = NULL;
  402. X        } else {
  403. X            /*
  404. X             * Null-terminate the command and skip
  405. X             * whitespace to arg or end of line.
  406. X             */
  407. X            *arg++ = '\0';
  408. X            skipblanks(arg);
  409. X
  410. X            /*
  411. X             * There was trailing whitespace,
  412. X             * but no args.
  413. X             */
  414. X            if (*arg == '\0') {
  415. X            arg = NULL;
  416. X            }
  417. X        }
  418. X        } else if (ecp->ec_arg_type == ec_nonalnum && exclam) {
  419. X        /*
  420. X         * We don't normally touch the arguments for
  421. X         * this type, but we have to null-terminate
  422. X         * the '!' at least.
  423. X         */
  424. X        *arg++ = '\0';
  425. X        }
  426. X
  427. X        if (arg != NULL) {
  428. X        /*
  429. X         * Perform expansions on the argument string.
  430. X         */
  431. X        if (ecp->ec_flags & EC_INTEXP) {
  432. X            arg = expand_percents(arg);
  433. X        }
  434. X        if (ecp->ec_flags & EC_FILEXP) {
  435. X            arg = fexpand(arg);
  436. X        }
  437. X
  438. X        if (ecp->ec_arg_type == ec_strings) {
  439. X            makeargv(arg, &argc, &argv, " \t");
  440. X        }
  441. X        }
  442. X    }
  443. X    }
  444. X
  445. X    savecho = echo;
  446. X
  447. X    /*
  448. X     * Now do the command.
  449. X     */
  450. X    switch (command) {
  451. X    case EX_SHCMD:
  452. X    /*
  453. X     * If a line range was specified, this must be a pipe command.
  454. X     * Otherwise, it's just a simple shell command.
  455. X     */
  456. X    if (l_line != NULL) {
  457. X        specify_pipe_range(curwin, l_line, u_line);
  458. X        do_pipe(curwin, arg);
  459. X    } else {
  460. X        do_shcmd(curwin, arg);
  461. X    }
  462. X    break;
  463. X
  464. X    case EX_ARGS:
  465. X    do_args(curwin);
  466. X    break;
  467. X
  468. X    case EX_BUFFER:
  469. X    if (arg != NULL)
  470. X        echo &= ~(e_SCROLL | e_REPORT | e_SHOWINFO);
  471. X    (void) do_buffer(curwin, arg);
  472. X    move_window_to_cursor(curwin);
  473. X    update_window(curwin);
  474. X    break;
  475. X
  476. X    case EX_CHDIR:
  477. X    {
  478. X    char    *error;
  479. X
  480. X    if ((error = do_chdir(arg)) != NULL) {
  481. X        badcmd(interactive, error);
  482. X    } else if (interactive) {
  483. X        char    *dirp;
  484. X
  485. X        if ((dirp = alloc(MAXPATHLEN + 2)) != NULL &&
  486. X        getcwd(dirp, MAXPATHLEN + 2) != NULL) {
  487. X        show_message(curwin, "%s", dirp);
  488. X        }
  489. X        if (dirp) {
  490. X        free(dirp);
  491. X        }
  492. X    }
  493. X    break;
  494. X    }
  495. X
  496. X    case EX_CLOSE:
  497. X    do_close_window(curwin, exclam);
  498. X    break;
  499. X
  500. X    case EX_COMMENT:        /* This one is easy ... */
  501. X    break;
  502. X
  503. X    case EX_COMPARE:
  504. X    do_compare();
  505. X    break;
  506. X
  507. X    case EX_COPY:
  508. X    do_cdmy('c', l_line, u_line, a_line);
  509. X    break;
  510. X
  511. X    case EX_DELETE:
  512. X    do_cdmy('d', l_line, u_line, (Line *) NULL);
  513. X    break;
  514. X
  515. X    case EX_ECHO:            /* echo arguments on command line */
  516. X    {
  517. X    int    i;
  518. X
  519. X    flexclear(&curwin->w_statusline);
  520. X    for (i = 0; i < argc; i++) {
  521. X        if (!lformat(&curwin->w_statusline, "%s ", argv[i])
  522. X            || flexlen(&curwin->w_statusline) >= curwin->w_ncols) {
  523. X        break;
  524. X        }
  525. X    }
  526. X    update_sline(curwin);
  527. X    break;
  528. X    }
  529. X
  530. X    case EX_EDIT:
  531. X    case EX_VISUAL:            /* treat :vi as :edit */
  532. X    echo &= ~(e_SCROLL | e_REPORT | e_SHOWINFO);
  533. X    (void) do_edit(curwin, exclam, arg);
  534. X    move_window_to_cursor(curwin);
  535. X    update_buffer(curbuf);
  536. X#if 0
  537. X    show_file_info(curwin);
  538. X#endif
  539. X    break;
  540. X
  541. X    case EX_FILE:
  542. X    if (arg != NULL) {
  543. X        if (curbuf->b_filename != NULL)
  544. X        free(curbuf->b_filename);
  545. X        curbuf->b_filename = strsave(arg);
  546. X        if (curbuf->b_tempfname != NULL) {
  547. X        free(curbuf->b_tempfname);
  548. X        curbuf->b_tempfname = NULL;
  549. X        }
  550. X    }
  551. X    show_file_info(curwin);
  552. X    break;
  553. X
  554. X    case EX_GLOBAL:
  555. X    do_global(curwin, l_line, u_line, arg, !exclam);
  556. X    break;
  557. X
  558. X    case EX_HELP:
  559. X    do_help(curwin);
  560. X    break;
  561. X
  562. X    case EX_MAP:
  563. X    xvi_map(argc, argv, exclam, interactive);
  564. X    break;
  565. X
  566. X    case EX_UNMAP:
  567. X    xvi_unmap(argc, argv, exclam, interactive);
  568. X    break;
  569. X
  570. X    case EX_MARK:
  571. X    case EX_K:
  572. X    {
  573. X    Posn    pos;
  574. X
  575. X    pos.p_index = 0;
  576. X    if (l_line == NULL) {
  577. X        pos.p_line = curwin->w_cursor->p_line;
  578. X    } else {
  579. X        pos.p_line = l_line;
  580. X    }
  581. X    (void) setmark(arg[0], curbuf, &pos);
  582. X    break;
  583. X    }
  584. X
  585. X    case EX_MOVE:
  586. X    do_cdmy('m', l_line, u_line, a_line);
  587. X    break;
  588. X
  589. X    case EX_NEXT:
  590. X    /*
  591. X     * do_next() handles turning off the appropriate bits
  592. X     * in echo, & also calls move_window_to_cursor() &
  593. X     * update_buffer() as required, so we don't have to
  594. X     * do any of that here.
  595. X     */
  596. X    do_next(curwin, argc, argv, exclam);
  597. X    break;
  598. X
  599. X    case EX_PRESERVE:
  600. X    if (do_preserve())
  601. X        show_file_info(curwin);
  602. X    break;
  603. X
  604. X    case EX_LIST:
  605. X    case EX_PRINT:
  606. X    case EX_NUMBER:
  607. X    if (l_line == NULL) {
  608. X        curline = curwin->w_cursor->p_line;
  609. X        lastline = curline->l_next;
  610. X    } else if (u_line ==  NULL) {
  611. X        curline = l_line;
  612. X        lastline = l_line->l_next;
  613. X    } else {
  614. X        curline = l_line;
  615. X        lastline = u_line->l_next;
  616. X    }
  617. X    do_line_numbers = (Pb(P_number) || command == EX_NUMBER);
  618. X    disp_init(curwin, show_line, (int) curwin->w_ncols,
  619. X                command == EX_LIST || Pb(P_list));
  620. X    break;
  621. X
  622. X    case EX_PUT:
  623. X    {
  624. X    Posn    where;
  625. X
  626. X    if (l_line != NULL) {
  627. X        where.p_index = 0;
  628. X        where.p_line = l_line;
  629. X    } else {
  630. X        where.p_index = curwin->w_cursor->p_index;
  631. X        where.p_line = curwin->w_cursor->p_line;
  632. X    }
  633. X    do_put(curwin, &where, FORWARD, '@');
  634. X    break;
  635. X    }
  636. X
  637. X    case EX_QUIT:
  638. X    do_quit(curwin, exclam);
  639. X    break;
  640. X
  641. X    case EX_REWIND:
  642. X    do_rewind(curwin, exclam);
  643. X    break;
  644. X
  645. X    case EX_READ:
  646. X    if (arg == NULL) {
  647. X        badcmd(interactive, "Unrecognized command");
  648. X        break;
  649. X    }
  650. X    do_read(curwin, arg, (l_line != NULL) ? l_line :
  651. X                        curwin->w_cursor->p_line);
  652. X    break;
  653. X
  654. X    case EX_SET:
  655. X    do_set(curwin, argc, argv, interactive);
  656. X    break;
  657. X
  658. X    case EX_SHELL:
  659. X    do_shell(curwin);
  660. X    break;
  661. X
  662. X    case EX_SOURCE:
  663. X    if (arg == NULL) {
  664. X        badcmd(interactive, "Missing filename");
  665. X    } else if (do_source(interactive, arg) && interactive) {
  666. X        show_file_info(curwin);
  667. X    }
  668. X    break;
  669. X
  670. X    case EX_SPLIT:
  671. X    /*
  672. X     * "split".
  673. X     */
  674. X    do_split_window(curwin);
  675. X    break;
  676. X
  677. X    case EX_SUBSTITUTE:
  678. X    case EX_AMPERSAND:
  679. X    case EX_TILDE:
  680. X    {
  681. X    long        nsubs;
  682. X    register long    (*func) P((Xviwin *, Line *, Line *, char *));
  683. X
  684. X    switch (command) {
  685. X    case EX_SUBSTITUTE:
  686. X        func = do_substitute;
  687. X        break;
  688. X    case EX_AMPERSAND:
  689. X        func = do_ampersand;
  690. X        break;
  691. X    case EX_TILDE:
  692. X        func = do_tilde;
  693. X    }
  694. X
  695. X    nsubs = (*func)(curwin, l_line, u_line, arg);
  696. X    update_buffer(curbuf);
  697. X    cursupdate(curwin);
  698. X    begin_line(curwin, TRUE);
  699. X    if (nsubs >= Pn(P_report)) {
  700. X        show_message(curwin, "%ld substitution%c",
  701. X            nsubs,
  702. X            (nsubs > 1) ? 's' : ' ');
  703. X    }
  704. X    break;
  705. X    }
  706. X
  707. X    case EX_SUSPEND:
  708. X    do_suspend(curwin);
  709. X    break;
  710. X
  711. X    case EX_TAG:
  712. X    (void) do_tag(curwin, arg, exclam, TRUE, TRUE);
  713. X    break;
  714. X
  715. X    case EX_V:
  716. X    do_global(curwin, l_line, u_line, arg, FALSE);
  717. X    break;
  718. X
  719. X    case EX_VERSION:
  720. X    show_message(curwin, Version);
  721. X    break;
  722. X
  723. X    case EX_WN:
  724. X    /*
  725. X     * This is not a standard "vi" command, but it
  726. X     * is provided in PC vi, and it's quite useful.
  727. X     */
  728. X    if (do_write(curwin, (char *) NULL, (Line *) NULL, (Line *) NULL,
  729. X                                exclam)) {
  730. X        /*
  731. X         * See comment for EX_NEXT (above).
  732. X         */
  733. X        do_next(curwin, 0, argv, exclam);
  734. X#if 0
  735. X        move_window_to_cursor(curwin);
  736. X        update_buffer(curbuf);
  737. X#endif
  738. X    }
  739. X    break;
  740. X
  741. X    case EX_WQ:
  742. X    do_wq(curwin, arg, exclam);
  743. X    break;
  744. X
  745. X    case EX_WRITE:
  746. X    (void) do_write(curwin, arg, l_line, u_line, exclam);
  747. X    break;
  748. X
  749. X    case EX_XIT:
  750. X    do_xit(curwin);
  751. X    break;
  752. X
  753. X    case EX_YANK:
  754. X    do_cdmy('y', l_line, u_line, (Line *) NULL);
  755. X    break;
  756. X
  757. X    case EX_EXBUFFER:
  758. X    yp_stuff_input(curwin, arg[0], FALSE);
  759. X    break;
  760. X
  761. X    case EX_EQUALS:
  762. X    do_equals(curwin, l_line);
  763. X    break;
  764. X
  765. X    case EX_LSHIFT:
  766. X    case EX_RSHIFT:
  767. X    if (l_line == NULL) {
  768. X        l_line = curwin->w_cursor->p_line;
  769. X    }
  770. X    if (u_line == NULL) {
  771. X        u_line = l_line;
  772. X    }
  773. X    tabinout((command == EX_LSHIFT) ? '<' : '>', l_line, u_line);
  774. X    begin_line(curwin, TRUE);
  775. X    update_buffer(curbuf);
  776. X    break;
  777. X
  778. X    case EX_NOCMD:
  779. X    /*
  780. X     * If we got a line, but no command, then go to the line.
  781. X     */
  782. X    if (l_line != NULL) {
  783. X        if (l_line == curbuf->b_line0) {
  784. X        l_line = l_line->l_next;
  785. X        }
  786. X        move_cursor(curwin, l_line, 0);
  787. X        begin_line(curwin, TRUE);
  788. X    }
  789. X    break;
  790. X
  791. X    case EX_ENOTFOUND:
  792. X    badcmd(interactive, "Unrecognized command");
  793. X    break;
  794. X
  795. X    case EX_EAMBIGUOUS:
  796. X    badcmd(interactive, "Ambiguous command");
  797. X    break;
  798. X
  799. X    case EX_ECANTFORCE:
  800. X    badcmd(interactive, "Inappropriate use of !");
  801. X    break;
  802. X
  803. X    case EX_EBADARGS:
  804. X    badcmd(interactive, "Inappropriate arguments given");
  805. X    break;
  806. X
  807. X    default:
  808. X    /*
  809. X     * Decoded successfully, but unknown to us. Whoops!
  810. X     */
  811. X    badcmd(interactive, "Internal error - unimplemented command.");
  812. X    break;
  813. X
  814. X    case EX_ABBREVIATE:
  815. X    case EX_APPEND:
  816. X    case EX_CHANGE:
  817. X    case EX_EX:
  818. X    case EX_GOTO:
  819. X    case EX_INSERT:
  820. X    case EX_JOIN:
  821. X    case EX_OPEN:
  822. X    case EX_RECOVER:
  823. X    case EX_UNABBREV:
  824. X    case EX_UNDO:
  825. X    case EX_Z:
  826. X    badcmd(interactive, "Unimplemented command.");
  827. X    break;
  828. X    }
  829. X
  830. X    echo = savecho;
  831. X
  832. X    if (argc > 0 && argv != NULL) {
  833. X    free((char *) argv);
  834. X    }
  835. X}
  836. X
  837. X/*
  838. X * Find the correct command for the given string, and return it.
  839. X *
  840. X * Updates string pointer to point to 1st char after command.
  841. X *
  842. X * Updates boolean pointed to by forcep according
  843. X * to whether an '!' was given after the command;
  844. X * if an '!' is given for a command which can't take it,
  845. X * this is an error, and EX_ECANTFORCE is returned.
  846. X * For unknown commands, EX_ENOTFOUND is returned.
  847. X * For ambiguous commands, EX_EAMBIGUOUS is returned.
  848. X *
  849. X * Also updates *cmdp to point at entry in command table.
  850. X */
  851. Xstatic int
  852. Xdecode_command(str, forcep, cmdp)
  853. Xchar        **str;
  854. Xbool_t        *forcep;
  855. Xstruct    ecmd    **cmdp;
  856. X{
  857. X    struct ecmd    *cmdptr;
  858. X    struct ecmd    *last_match = NULL;
  859. X    bool_t    last_exclam = FALSE;
  860. X    int        nmatches = 0;
  861. X    char    *last_delimiter = *str;
  862. X
  863. X    for (cmdptr = cmdtable; cmdptr->ec_name != NULL; cmdptr++) {
  864. X    char    *name = cmdptr->ec_name;
  865. X    char    *strp;
  866. X    bool_t    matched;
  867. X
  868. X    strp = *str;
  869. X
  870. X    while (*strp == *name && *strp != '\0') {
  871. X        strp++;
  872. X        name++;
  873. X    }
  874. X
  875. X    matched = (
  876. X        /*
  877. X         * we've got a full match, or ...
  878. X         */
  879. X        *strp == '\0'
  880. X        ||
  881. X        /*
  882. X         * ... a whitespace delimiter, or ...
  883. X         */
  884. X        is_space(*strp)
  885. X        ||
  886. X        (
  887. X        /*
  888. X         * ... at least one character has been
  889. X         * matched, and ...
  890. X         */
  891. X        name > cmdptr->ec_name
  892. X        &&
  893. X        (
  894. X            (
  895. X            /*
  896. X             * ... this command can accept a
  897. X             * '!' qualifier, and we've found
  898. X             * one ...
  899. X             */
  900. X            (cmdptr->ec_flags & EC_EXCLAM)
  901. X            &&
  902. X            *strp == '!'
  903. X            )
  904. X            ||
  905. X            (
  906. X            /*
  907. X             * ... or it can take a
  908. X             * non-alphanumeric delimiter
  909. X             * (like '/') ...
  910. X             */
  911. X            cmdptr->ec_arg_type == ec_nonalnum
  912. X            &&
  913. X            !is_alnum(*strp)
  914. X            )
  915. X            ||
  916. X            (
  917. X            /*
  918. X             * ... or it doesn't need any
  919. X             * delimiter ...
  920. X             */
  921. X            cmdptr->ec_arg_type == ec_rest
  922. X            )
  923. X            ||
  924. X            (
  925. X            /*
  926. X             * ... or we've got a full match,
  927. X             * & the command expects a single
  928. X             * lower-case letter as an
  929. X             * argument, and we've got one ...
  930. X             */
  931. X            cmdptr->ec_arg_type == ec_1lower
  932. X            &&
  933. X            *name == '\0'
  934. X            &&
  935. X            is_lower(*strp)
  936. X            )
  937. X            ||
  938. X            (
  939. X            /*
  940. X             * ... or we've got a partial match,
  941. X             * and the command expects a line
  942. X             * specifier as an argument, and the
  943. X             * next character is not alphabetic.
  944. X             */
  945. X            cmdptr->ec_arg_type == ec_line
  946. X            &&
  947. X            !is_alpha(*strp)
  948. X            )
  949. X        )
  950. X        )
  951. X    );
  952. X
  953. X    if (!matched)
  954. X        continue;
  955. X
  956. X    if (last_match == NULL ||
  957. X        (last_match != NULL &&
  958. X         last_match->ec_priority < cmdptr->ec_priority)) {
  959. X        /*
  960. X         * No previous match, or this one is better.
  961. X         */
  962. X        last_match = cmdptr;
  963. X        last_exclam = (*strp == '!');
  964. X        last_delimiter = strp;
  965. X        nmatches = 1;
  966. X
  967. X        /*
  968. X         * If this is a complete match, we don't
  969. X         * need to search the rest of the table.
  970. X         */
  971. X        if (*name == '\0')
  972. X        break;
  973. X
  974. X    } else if (last_match != NULL &&
  975. X           last_match->ec_priority == cmdptr->ec_priority) {
  976. X        /*
  977. X         * Another match with the same priority - remember it.
  978. X         */
  979. X        nmatches++;
  980. X    }
  981. X    }
  982. X
  983. X    /*
  984. X     * For us to have found a good match, there must have been
  985. X     * exactly one match at a certain priority, and if an '!'
  986. X     * was used, it must be allowed by that match.
  987. X     */
  988. X    if (last_match == NULL) {
  989. X    return(EX_ENOTFOUND);
  990. X    } else if (nmatches != 1) {
  991. X    return(EX_EAMBIGUOUS);
  992. X    } else if (last_exclam && ! (last_match->ec_flags & EC_EXCLAM)) {
  993. X    return(EX_ECANTFORCE);
  994. X    } else {
  995. X    *forcep = last_exclam;
  996. X    *str = last_delimiter;
  997. X    *cmdp = last_match;
  998. X    return(last_match->ec_command);
  999. X    }
  1000. X}
  1001. X
  1002. X/*
  1003. X * get_range - parse a range specifier
  1004. X *
  1005. X * Ranges are of the form
  1006. X *
  1007. X * ADDRESS1,ADDRESS2
  1008. X * ADDRESS        (equivalent to "ADDRESS,ADDRESS")
  1009. X * ADDRESS,        (equivalent to "ADDRESS,.")
  1010. X * ,ADDRESS        (equivalent to ".,ADDRESS")
  1011. X * ,            (equivalent to ".")
  1012. X * %            (equivalent to "1,$")
  1013. X *
  1014. X * where ADDRESS is
  1015. X *
  1016. X * /regular expression/ [INCREMENT]
  1017. X * ?regular expression? [INCREMENT]
  1018. X * $   [INCREMENT]
  1019. X * 'x  [INCREMENT]    (where x denotes a currently defined mark)
  1020. X * .   [INCREMENT]
  1021. X * INCREMENT        (equivalent to . INCREMENT)
  1022. X * number [INCREMENT]
  1023. X *
  1024. X * and INCREMENT is
  1025. X *
  1026. X * + number
  1027. X * - number
  1028. X * +            (equivalent to +1)
  1029. X * -            (equivalent to -1)
  1030. X * ++            (equivalent to +2)
  1031. X * --            (equivalent to -2)
  1032. X *
  1033. X * etc.
  1034. X *
  1035. X * The pointer *cpp is updated to point to the first character following
  1036. X * the range spec. If an initial address is found, but no second, the
  1037. X * upper bound is equal to the lower, except if it is followed by ','.
  1038. X *
  1039. X * Return FALSE if an error occurred, otherwise TRUE.
  1040. X */
  1041. Xstatic bool_t
  1042. Xget_range(cpp)
  1043. Xregister char    **cpp;
  1044. X{
  1045. X    register char    *cp;
  1046. X    char        sepchar;
  1047. X
  1048. X#define skipp    { cp = *cpp; skipblanks(cp); *cpp = cp; }
  1049. X
  1050. X    skipp;
  1051. X
  1052. X    if (*cp == '%') {
  1053. X    /*
  1054. X     * "%" is the same as "1,$".
  1055. X     */
  1056. X    l_line = curbuf->b_file;
  1057. X    u_line = curbuf->b_lastline->l_prev;
  1058. X    ++*cpp;
  1059. X    return TRUE;
  1060. X    }
  1061. X
  1062. X    if (!get_line(cpp, &l_line)) {
  1063. X    return FALSE;
  1064. X    }
  1065. X
  1066. X    skipp;
  1067. X
  1068. X    sepchar = *cp;
  1069. X    if (sepchar != ',' && sepchar != ';') {
  1070. X    u_line = l_line;
  1071. X    return TRUE;
  1072. X    }
  1073. X
  1074. X    ++*cpp;
  1075. X
  1076. X    if (l_line == NULL) {
  1077. X    /*
  1078. X     * So far, we've got ",".
  1079. X     *
  1080. X     * ",address" is equivalent to ".,address".
  1081. X     */
  1082. X    l_line = curwin->w_cursor->p_line;
  1083. X    }
  1084. X
  1085. X    if (sepchar == ';') {
  1086. X    move_cursor(curwin, (l_line != curbuf->b_line0) ?
  1087. X            l_line : l_line->l_next, 0);
  1088. X    }
  1089. X
  1090. X    skipp;
  1091. X    if (!get_line(cpp, &u_line)) {
  1092. X    return FALSE;
  1093. X    }
  1094. X    if (u_line == NULL) {
  1095. X    /*
  1096. X     * "address," is equivalent to "address,.".
  1097. X     */
  1098. X    u_line = curwin->w_cursor->p_line;
  1099. X    }
  1100. X
  1101. X    /*
  1102. X     * Check for reverse ordering.
  1103. X     */
  1104. X    if (earlier(u_line, l_line)) {
  1105. X    Line    *tmp;
  1106. X
  1107. X    tmp = l_line;
  1108. X    l_line = u_line;
  1109. X    u_line = tmp;
  1110. X    }
  1111. X
  1112. X    skipp;
  1113. X    return TRUE;
  1114. X}
  1115. X
  1116. Xstatic bool_t
  1117. Xget_line(cpp, lpp)
  1118. X    char        **cpp;
  1119. X    Line        **lpp;
  1120. X{
  1121. X    Line        *pos;
  1122. X    char        *cp;
  1123. X    char        c;
  1124. X    long        lnum;
  1125. X
  1126. X    cp = *cpp;
  1127. X
  1128. X    /*
  1129. X     * Determine the basic form, if present.
  1130. X     */
  1131. X    switch (c = *cp++) {
  1132. X
  1133. X    case '/':
  1134. X    case '?':
  1135. X    pos = linesearch(curwin, (c == '/') ? FORWARD : BACKWARD,
  1136. X                    &cp);
  1137. X    if (pos == NULL) {
  1138. X        return FALSE;
  1139. X    }
  1140. X    break;
  1141. X
  1142. X    case '$':
  1143. X    pos = curbuf->b_lastline->l_prev;
  1144. X    break;
  1145. X
  1146. X    /*
  1147. X     * "+n" is equivalent to ".+n".
  1148. X     */
  1149. X    case '+':
  1150. X    case '-':
  1151. X    cp--;
  1152. X     /* fall through ... */
  1153. X    case '.':
  1154. X    pos = curwin->w_cursor->p_line;
  1155. X    break;
  1156. X
  1157. X    case '\'': {
  1158. X    Posn        *lp;
  1159. X
  1160. X    lp = getmark(*cp++, curbuf);
  1161. X    if (lp == NULL) {
  1162. X        show_error(curwin, "Unknown mark");
  1163. X        return FALSE;
  1164. X    }
  1165. X    pos = lp->p_line;
  1166. X    break;
  1167. X    }
  1168. X    case '0': case '1': case '2': case '3': case '4':
  1169. X    case '5': case '6': case '7': case '8': case '9':
  1170. X    for (lnum = c - '0'; is_digit(*cp); cp++)
  1171. X        lnum = lnum * 10 + *cp - '0';
  1172. X
  1173. X    if (lnum == 0) {
  1174. X        pos = curbuf->b_line0;
  1175. X    } else {
  1176. X        pos = gotoline(curbuf, lnum);
  1177. X    }
  1178. X    break;
  1179. X    
  1180. X    default:
  1181. X    return TRUE;
  1182. X    }
  1183. X
  1184. X    skipblanks(cp);
  1185. X
  1186. X    if (*cp == '-' || *cp == '+') {
  1187. X    char    dirchar = *cp++;
  1188. X
  1189. X    skipblanks(cp);
  1190. X    if (is_digit(*cp)) {
  1191. X        for (lnum = 0; is_digit(*cp); cp++) {
  1192. X        lnum = lnum * 10 + *cp - '0';
  1193. X        }
  1194. X    } else {
  1195. X        for (lnum = 1; *cp == dirchar; cp++) {
  1196. X        lnum++;
  1197. X        }
  1198. X    }
  1199. X
  1200. X    if (dirchar == '-')
  1201. X        lnum = -lnum;
  1202. X
  1203. X    pos = gotoline(curbuf, lineno(curbuf, pos) + lnum);
  1204. X    }
  1205. X
  1206. X    *cpp = cp;
  1207. X    *lpp = pos;
  1208. X    return TRUE;
  1209. X}
  1210. X
  1211. X/*
  1212. X * This routine is called for ambiguous, unknown,
  1213. X * badly defined or unimplemented commands.
  1214. X */
  1215. Xstatic void
  1216. Xbadcmd(interactive, str)
  1217. Xbool_t    interactive;
  1218. Xchar    *str;
  1219. X{
  1220. X    if (interactive) {
  1221. X    show_error(curwin, str);
  1222. X    }
  1223. X}
  1224. X
  1225. Xstatic char *
  1226. Xshow_line()
  1227. X{
  1228. X    Line    *lp;
  1229. X
  1230. X    if (curline == lastline) {
  1231. X    return(NULL);
  1232. X    }
  1233. X
  1234. X    lp = curline;
  1235. X    curline = curline->l_next;
  1236. X
  1237. X    if (do_line_numbers) {
  1238. X    static Flexbuf    nu_line;
  1239. X
  1240. X    flexclear(&nu_line);
  1241. X    (void) lformat(&nu_line, NUM_FMT, lineno(curbuf, lp));
  1242. X    (void) lformat(&nu_line, "%s", lp->l_text);
  1243. X    return flexgetstr(&nu_line);
  1244. X    } else {
  1245. X    return(lp->l_text);
  1246. X    }
  1247. X}
  1248. X
  1249. Xstatic char *
  1250. Xexpand_percents(str)
  1251. Xchar    *str;
  1252. X{
  1253. X    static Flexbuf    newstr;
  1254. X    register char    *from;
  1255. X    register bool_t    escaped;
  1256. X
  1257. X    if (strpbrk(str, "%#") == (char *) NULL) {
  1258. X    return str;
  1259. X    }
  1260. X    flexclear(&newstr);
  1261. X    escaped = FALSE;
  1262. X    for (from = str; *from != '\0'; from++) {
  1263. X    if (!escaped) {
  1264. X        if (*from == '%' && curbuf->b_filename != NULL) {
  1265. X        (void) lformat(&newstr, "%s", curbuf->b_filename);
  1266. X        } else if (*from == '#' && altfilename != NULL) {
  1267. X        (void) lformat(&newstr, "%s", altfilename);
  1268. X        } else if (*from == '\\') {
  1269. X        escaped = TRUE;
  1270. X        } else {
  1271. X        (void) flexaddch(&newstr, *from);
  1272. X        }
  1273. X    } else {
  1274. X        if (*from != '%' && *from != '#') {
  1275. X        (void) flexaddch(&newstr, '\\');
  1276. X        }
  1277. X        (void) flexaddch(&newstr, *from);
  1278. X        escaped = FALSE;
  1279. X    }
  1280. X    }
  1281. X    return flexgetstr(&newstr);
  1282. X}
  1283. END_OF_FILE
  1284.   if test 27270 -ne `wc -c <'xvi/src/cmdline.c'`; then
  1285.     echo shar: \"'xvi/src/cmdline.c'\" unpacked with wrong size!
  1286.   fi
  1287.   # end of 'xvi/src/cmdline.c'
  1288. fi
  1289. if test -f 'xvi/src/param.c' -a "${1}" != "-c" ; then 
  1290.   echo shar: Will not clobber existing file \"'xvi/src/param.c'\"
  1291. else
  1292.   echo shar: Extracting \"'xvi/src/param.c'\" \(23114 characters\)
  1293.   sed "s/^X//" >'xvi/src/param.c' <<'END_OF_FILE'
  1294. X/* Copyright (c) 1990,1991,1992 Chris and John Downey */
  1295. X#ifndef lint
  1296. Xstatic char *sccsid = "@(#)param.c    2.1 (Chris & John Downey) 7/29/92";
  1297. X#endif
  1298. X
  1299. X/***
  1300. X
  1301. X* program name:
  1302. X    xvi
  1303. X* function:
  1304. X    PD version of UNIX "vi" editor, with extensions.
  1305. X* module name:
  1306. X    param.c
  1307. X* module function:
  1308. X    Code to handle user-settable parameters. This is all pretty much
  1309. X    table-driven. To add a new parameter, put it in the params array,
  1310. X    and add a macro for it in param.h.
  1311. X
  1312. X    The idea of the parameter table is that access to any particular
  1313. X    parameter has to be fast, so it is done with a table lookup. This
  1314. X    unfortunately means that the index of each parameter is recorded
  1315. X    as a macro in param.h, so that file must be changed at the same
  1316. X    time as the table below, and in the same way.
  1317. X
  1318. X    When a parameter is changed, a function is called to do the actual
  1319. X    work; this function is part of the parameter structure.  For many
  1320. X    parameters, it's just a simple function that prints "not implemented";
  1321. X    for most others, there are "standard" functions to set bool, numeric
  1322. X    and string parameters, with a certain amount of checking.
  1323. X
  1324. X    No bounds checking is done here; we should really include limits
  1325. X    to numeric parameters in the table. Maybe this will come later.
  1326. X
  1327. X    The data structures will be changed again shortly to enable
  1328. X    buffer- and window-local parameters to be implemented.
  1329. X
  1330. X    One problem with numeric parameters is that they are of type "int";
  1331. X    this obviously places some restrictions on the sort of things they
  1332. X    may be used for, and it may be necessary at some point to change
  1333. X    this type to something like "unsigned long".
  1334. X
  1335. X* history:
  1336. X    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  1337. X    Originally by Tim Thompson (twitch!tjt)
  1338. X    Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  1339. X    Heavily modified by Chris & John Downey
  1340. X
  1341. X***/
  1342. X
  1343. X#include "xvi.h"
  1344. X
  1345. X#define nofunc    PFUNCADDR(NULL)
  1346. X
  1347. X/*
  1348. X * Default settings for string parameters.
  1349. X * These are set by the exported function init_params(),
  1350. X * which must be called before any parameters are accessed.
  1351. X */
  1352. X#define    DEF_TAGS    "tags,/usr/lib/tags"
  1353. X#define    DEF_PARA    "^($|\\.([ILPQ]P|LI|[plib]p))"
  1354. X#define    DEF_SECTIONS    "^({|\\.([NS]H|HU|nh|sh))"
  1355. X#define    DEF_SENTENCES    "\\<[A-Z]"
  1356. X
  1357. X/*
  1358. X * Default setting for roscolour parameter is the same
  1359. X * as the statuscolour if not specified otherwise.
  1360. X */
  1361. X#ifndef    DEF_ROSCOLOUR
  1362. X#define    DEF_ROSCOLOUR    DEF_STCOLOUR
  1363. X#endif
  1364. X
  1365. X/*
  1366. X * Default settings for showing control- and meta-characters are
  1367. X * as for "normal" vi, i.e. "old" xvi without SHOW_META_CHARS set.
  1368. X */
  1369. X#ifndef    DEF_CCHARS
  1370. X#   define    DEF_CCHARS    FALSE
  1371. X#endif
  1372. X#ifndef    DEF_MCHARS
  1373. X#   define    DEF_MCHARS    FALSE
  1374. X#endif
  1375. X
  1376. X/*
  1377. X * Internal functions.
  1378. X */
  1379. Xstatic    int    strtoi P((char **));
  1380. Xstatic    bool_t    _do_set P((Xviwin *, char *, bool_t));
  1381. Xstatic    char    *parmstring P((Param *, int));
  1382. Xstatic    void    enum_usage P((Xviwin*, Param *));
  1383. Xstatic    bool_t    not_imp P((Xviwin *, Paramval, bool_t));
  1384. Xstatic    bool_t    set_magic P((Xviwin *, Paramval, bool_t));
  1385. Xstatic    bool_t    set_rt P((Xviwin *, Paramval, bool_t));
  1386. Xstatic    char    *par_show P((void));
  1387. X
  1388. X/*
  1389. X * These are the available parameters. The following are non-standard:
  1390. X *
  1391. X *    autosplit format helpfile jumpscroll preserve
  1392. X *    preservetime regextype vbell edit
  1393. X *    colour statuscolour roscolour systemcolour
  1394. X */
  1395. XParam    params[] = {
  1396. X/*  fullname        shortname       flags       value           function ... */
  1397. X{   "ada",          "ada",          P_BOOL,     0,              not_imp,   },
  1398. X{   "adapath",      "adapath",      P_STRING,   0,              not_imp,   },
  1399. X{   "autoindent",   "ai",           P_BOOL,     0,              nofunc,    },
  1400. X{   "autoprint",    "ap",           P_BOOL,     0,              not_imp,   },
  1401. X{   "autosplit",    "as",           P_NUM,      2,              nofunc,    },
  1402. X{   "autowrite",    "aw",           P_BOOL,     0,              not_imp,   },
  1403. X{   "beautify",     "bf",           P_BOOL,     0,              not_imp,   },
  1404. X{   "cchars",       "cchars",       P_BOOL,     DEF_CCHARS,     nofunc,    },
  1405. X{   "colour",       "co",           P_NUM,      DEF_COLOUR,     nofunc,    },
  1406. X{   "directory",    "dir",          P_STRING,   0,              not_imp,   },
  1407. X{   "edcompatible", "edcompatible", P_BOOL,     0,              not_imp,   },
  1408. X{   "edit",         "edit",         P_BOOL,     TRUE,           set_edit,  },
  1409. X{   "errorbells",   "eb",           P_BOOL,     0,              nofunc,    },
  1410. X{   "format",       "fmt",          P_ENUM,     0,              set_format,},
  1411. X{   "hardtabs",     "ht",           P_NUM,      0,              not_imp,   },
  1412. X{   "helpfile",     "hf",           P_STRING,   0,              nofunc,    },
  1413. X{   "ignorecase",   "ic",           P_BOOL,     0,              nofunc,    },
  1414. X{   "jumpscroll",   "js",           P_ENUM,     0,              nofunc,    },
  1415. X{   "lisp",         "lisp",         P_BOOL,     0,              not_imp,   },
  1416. X{   "list",         "ls",           P_BOOL,     0,              nofunc,    },
  1417. X{   "magic",        "magic",        P_BOOL,     TRUE,           set_magic, },
  1418. X{   "mchars",       "mchars",       P_BOOL,     DEF_MCHARS,     nofunc,    },
  1419. X{   "mesg",         "mesg",         P_BOOL,     0,              not_imp,   },
  1420. X{   "minrows",      "min",          P_NUM,      2,              nofunc,    },
  1421. X{   "modeline",     "modeline",     P_BOOL,     0,              not_imp,   },
  1422. X{   "number",       "nu",           P_BOOL,     0,              nofunc,    },
  1423. X{   "open",         "open",         P_BOOL,     0,              not_imp,   },
  1424. X{   "optimize",     "opt",          P_BOOL,     0,              not_imp,   },
  1425. X{   "paragraphs",   "para",         P_STRING,   0,              nofunc,    },
  1426. X{   "preserve",     "psv",          P_ENUM,     0,              nofunc,    },
  1427. X{   "preservetime", "psvt",         P_NUM,      5,              nofunc,    },
  1428. X{   "prompt",       "prompt",       P_BOOL,     0,              not_imp,   },
  1429. X{   "readonly",     "ro",           P_BOOL,     0,              nofunc,       },
  1430. X{   "redraw",       "redraw",       P_BOOL,     0,              not_imp,   },
  1431. X{   "regextype",    "rt",           P_ENUM,     0,              set_rt,    },
  1432. X{   "remap",        "remap",        P_BOOL,     0,              nofunc,    },
  1433. X{   "report",       "report",       P_NUM,      5,              nofunc,    },
  1434. X{   "roscolour",    "rst",          P_NUM,      DEF_ROSCOLOUR,  nofunc,    },
  1435. X{   "scroll",       "scroll",       P_NUM,      0,              not_imp,   },
  1436. X{   "sections",     "sections",     P_STRING,   0,              nofunc,    },
  1437. X{   "sentences",    "sentences",    P_STRING,   0,              nofunc,    },
  1438. X{   "shell",        "sh",           P_STRING,   0,              nofunc,    },
  1439. X{   "shiftwidth",   "sw",           P_NUM,      8,              nofunc,    },
  1440. X{   "showmatch",    "sm",           P_BOOL,     0,              nofunc,    },
  1441. X{   "slowopen",     "slowopen",     P_BOOL,     0,              not_imp,   },
  1442. X{   "sourceany",    "sourceany",    P_BOOL,     0,              not_imp,   },
  1443. X{   "statuscolour", "st",           P_NUM,      DEF_STCOLOUR,   nofunc,    },
  1444. X{   "systemcolour", "sy",           P_NUM,      DEF_SYSCOLOUR,  nofunc,    },
  1445. X{   "tabs",         "tabs",         P_BOOL,     TRUE,           nofunc,    },
  1446. X{   "tabstop",      "ts",           P_NUM,      8,              nofunc,    },
  1447. X{   "taglength",    "tlh",          P_NUM,      0,              nofunc,    },
  1448. X{   "tags",         "tags",         P_LIST,     0,              nofunc,    },
  1449. X{   "term",         "term",         P_STRING,   0,              not_imp,   },
  1450. X{   "terse",        "terse",        P_BOOL,     0,              not_imp,   },
  1451. X{   "timeout",      "timeout",      P_NUM,      DEF_TIMEOUT,    nofunc,    },
  1452. X{   "ttytype",      "ttytype",      P_STRING,   0,              not_imp,   },
  1453. X{   "vbell",        "vb",           P_BOOL,     0,              nofunc,    },
  1454. X{   "warn",         "warn",         P_BOOL,     0,              not_imp,   },
  1455. X{   "window",       "window",       P_NUM,      0,              not_imp,   },
  1456. X{   "wrapmargin",   "wm",           P_NUM,      0,              nofunc,    },
  1457. X{   "wrapscan",     "ws",           P_BOOL,     TRUE,           nofunc,    },
  1458. X{   "writeany",     "wa",           P_BOOL,     0,              not_imp,   },
  1459. X
  1460. X{   (char *) NULL,  (char *) NULL,  0,          0,              nofunc,    },
  1461. X
  1462. X};
  1463. X
  1464. X/*
  1465. X * Special initialisations for string, list and enum parameters,
  1466. X * which we cannot put in the table above because C does not
  1467. X * allow the initialisation of unions.
  1468. X */
  1469. Xstatic struct {
  1470. X    int        index;
  1471. X    char    *value;
  1472. X} init_str[] = {    /* strings and lists */
  1473. X    P_helpfile,        HELPFILE,
  1474. X    P_paragraphs,    DEF_PARA,
  1475. X    P_sections,        DEF_SECTIONS,
  1476. X    P_sentences,    DEF_SENTENCES,
  1477. X    P_tags,        DEF_TAGS,
  1478. X};
  1479. X#define    NSTRS    (sizeof(init_str) / sizeof(init_str[0]))
  1480. X
  1481. X/*
  1482. X * Names of values for the P_jumpscroll enumerated parameter.
  1483. X *
  1484. X * It is essential that these are in the same order as the js_...
  1485. X * symbolic constants defined in xvi.h.
  1486. X */
  1487. Xstatic char *js_strings[] =
  1488. X{
  1489. X    "off",        /* js_OFF */
  1490. X    "auto",        /* js_AUTO */
  1491. X    "on",        /* js_ON */
  1492. X    NULL
  1493. X};
  1494. X
  1495. Xstatic struct {
  1496. X    int        index;
  1497. X    int        value;
  1498. X    char    **elist;
  1499. X} init_enum[] = {    /* enumerations */
  1500. X    P_format,        DEF_TFF,    fmt_strings,
  1501. X    P_jumpscroll,    js_AUTO,    js_strings,
  1502. X    P_preserve,        psv_STANDARD,    psv_strings,
  1503. X    P_regextype,    rt_GREP,    rt_strings,
  1504. X};
  1505. X#define    NENUMS    (sizeof(init_enum) / sizeof(init_enum[0]))
  1506. X
  1507. X/*
  1508. X * These are used by par_show().
  1509. X */
  1510. Xstatic    bool_t    show_all;
  1511. Xstatic    Param    *curparam;
  1512. X
  1513. X/*
  1514. X * Initialise parameters.
  1515. X *
  1516. X * This function is called once from startup().
  1517. X */
  1518. Xvoid
  1519. Xinit_params()
  1520. X{
  1521. X    Paramval    pv;
  1522. X    Param    *pp;
  1523. X    int        i;
  1524. X
  1525. X    /*
  1526. X     * First go through the special string and enum initialisation
  1527. X     * tables, setting the values into the union field in the
  1528. X     * parameter structures.
  1529. X     */
  1530. X    for (i = 0; i < NSTRS; i++) {
  1531. X    set_param(init_str[i].index, init_str[i].value);
  1532. X    }
  1533. X    for (i = 0; i < NENUMS; i++) {
  1534. X    set_param(init_enum[i].index, init_enum[i].value,
  1535. X            init_enum[i].elist);
  1536. X    }
  1537. X
  1538. X    /*
  1539. X     * Call any special functions that have been set up for
  1540. X     * any parameters, using the default values included in
  1541. X     * the parameter table.
  1542. X     */
  1543. X    for (pp = ¶ms[0]; pp->p_fullname != NULL; pp++) {
  1544. X    if (pp->p_func != nofunc && pp->p_func != PFUNCADDR(not_imp)) {
  1545. X        switch (pp->p_flags & P_TYPE) {
  1546. X        case P_NUM:
  1547. X        case P_ENUM:
  1548. X        pv.pv_i = pp->p_value;
  1549. X        break;
  1550. X        case P_BOOL:
  1551. X        pv.pv_b = pp->p_value;
  1552. X        break;
  1553. X        case P_STRING:
  1554. X        pv.pv_s = pp->p_str;
  1555. X        break;
  1556. X        case P_LIST:
  1557. X        pv.pv_l = pp->p_list;
  1558. X        }
  1559. X        (void) (*pp->p_func)(curwin, pv, FALSE);
  1560. X    }
  1561. X    }
  1562. X}
  1563. X
  1564. Xvoid
  1565. Xdo_set(window, argc, argv, inter)
  1566. XXviwin    *window;
  1567. Xint    argc;        /* number of parameters to set */
  1568. Xchar    *argv[];    /* vector of parameter strings */
  1569. Xbool_t    inter;        /* TRUE if called interactively */
  1570. X{
  1571. X    int    count;
  1572. X
  1573. X    /*
  1574. X     * First check to see if there were any parameters to set,
  1575. X     * or if the user just wants us to display the parameters.
  1576. X     */
  1577. X    if (argc == 0 || (argc == 1 && (argv[0][0] == '\0' ||
  1578. X                strncmp(argv[0], "all", 3) == 0))) {
  1579. X    if (inter) {
  1580. X        int pcwidth;
  1581. X
  1582. X        show_all = (argc != 0 && argv[0][0] != '\0');
  1583. X        curparam = ¶ms[0];
  1584. X        pcwidth = (window->w_ncols < 90 ?
  1585. X            window->w_ncols :
  1586. X            (window->w_ncols < 135 ?
  1587. X                window->w_ncols / 2 :
  1588. X                window->w_ncols / 3));
  1589. X
  1590. X        disp_init(window, par_show, pcwidth, FALSE);
  1591. X    }
  1592. X
  1593. X    return;
  1594. X    }
  1595. X
  1596. X    for (count = 0; count < argc; count++) {
  1597. X    if (!_do_set(window, argv[count], inter)) {
  1598. X        break;
  1599. X    }
  1600. X    }
  1601. X
  1602. X    if (inter) {
  1603. X
  1604. X    /*
  1605. X     * Finally, update the screen in case we changed
  1606. X     * something like "tabstop" or "list" that will change
  1607. X     * its appearance. We don't always have to do this,
  1608. X     * but it's easier for now.
  1609. X     */
  1610. X    update_all();
  1611. X    }
  1612. X}
  1613. X
  1614. X/*
  1615. X * Convert a string to an integer. The string may encode the integer
  1616. X * in octal, decimal or hexadecimal form, in the same style as C. On
  1617. X * return, make the string pointer, which is passed to us by
  1618. X * reference, point to the first character which isn't valid for the
  1619. X * base the number seems to be in.
  1620. X */
  1621. Xstatic int
  1622. Xstrtoi(sp)
  1623. Xchar    **sp;
  1624. X{
  1625. X    register char    *s;
  1626. X    register int    i, c;
  1627. X    bool_t        neg;
  1628. X
  1629. X    i = 0;
  1630. X    neg = FALSE;
  1631. X    s = *sp;
  1632. X    c = *s;
  1633. X    while (is_space(c)) {
  1634. X    c = *++s;
  1635. X    }
  1636. X    if (c == '-') {
  1637. X    neg = TRUE;
  1638. X    c = *++s;
  1639. X    }
  1640. X    while (is_space(c)) {
  1641. X    c = *++s;
  1642. X    }
  1643. X    if (c == '0') {
  1644. X    switch (c = *++s) {
  1645. X    case 'x': case 'X':
  1646. X        /*
  1647. X         * We've got 0x ... or 0X ..., so it
  1648. X         * looks like a hex. number.
  1649. X         */
  1650. X        while ((c = *++s) != '\0' && is_xdigit(c)) {
  1651. X        i = (i * 16) + hex_to_bin(c);
  1652. X        }
  1653. X        break;
  1654. X
  1655. X    case '0': case '1': case '2': case '3':
  1656. X    case '4': case '5': case '6': case '7':
  1657. X        /*
  1658. X         * It looks like an octal number.
  1659. X         */
  1660. X        do {
  1661. X        i = (i * 8) + c - '0';
  1662. X        } while ((c = *++s) != '\0' && is_octdigit(c));
  1663. X        break;
  1664. X
  1665. X    default:
  1666. X        *sp = s;
  1667. X        return(0);
  1668. X    }
  1669. X    } else {
  1670. X    /*
  1671. X     * Assume it's decimal.
  1672. X     */
  1673. X    while (c != '\0' && is_digit(c)) {
  1674. X        i = (i * 10) + c - '0';
  1675. X        c = *++s;
  1676. X    }
  1677. X    }
  1678. X    *sp = s;
  1679. X    return(neg ? -i : i);
  1680. X}
  1681. X
  1682. X/*
  1683. X * Internal version of do_set(). Returns TRUE if set of specified
  1684. X * parameter was successful, otherwise FALSE.
  1685. X */
  1686. Xstatic bool_t
  1687. X_do_set(window, arg, inter)
  1688. XXviwin    *window;
  1689. Xchar    *arg;                /* parameter string */
  1690. Xbool_t    inter;                /* TRUE if called interactively */
  1691. X{
  1692. X    int        settype = 0;        /* type they want to set */
  1693. X    bool_t    bool_value;        /* value they want to set */
  1694. X    char    *str_value;        /* value they want to set */
  1695. X    Param    *pp;
  1696. X    Paramval    val;
  1697. X    char    *cp;
  1698. X    char    **ep;
  1699. X
  1700. X
  1701. X    /*
  1702. X     * "arg" points at the parameter we are going to try to set.
  1703. X     * Spot "no" and "=" keys.
  1704. X     */
  1705. X
  1706. X    /*
  1707. X     * Note that we will have to change this later if we
  1708. X     * want to implement "nomatch" and "nonomatch". :-(
  1709. X     */
  1710. X    if (strncmp(arg, "no", 2) == 0) {
  1711. X    settype = P_BOOL;
  1712. X    bool_value = FALSE;
  1713. X    arg += 2;
  1714. X    } else {
  1715. X    bool_value = TRUE;
  1716. X    }
  1717. X
  1718. X    str_value = strchr(arg, '=');
  1719. X    if (str_value != NULL) {
  1720. X    if (settype == P_BOOL) {
  1721. X        if (inter) {
  1722. X        show_error(window, "Can't give \"no\" and a value");
  1723. X        return(FALSE);
  1724. X        }
  1725. X    }
  1726. X
  1727. X    /*
  1728. X     * Null-terminate the parameter name
  1729. X     * and point str_value at the value to
  1730. X     * the right of the '='.
  1731. X     */
  1732. X    *str_value++ = '\0';
  1733. X    settype = P_STRING;
  1734. X
  1735. X    } else if (settype != P_BOOL) {
  1736. X
  1737. X    /*
  1738. X     * Not already set to P_BOOL, so we haven't seen a "no".
  1739. X     * No '=' sign, so assume we are setting a boolean
  1740. X     * parameter to TRUE.
  1741. X     */
  1742. X    settype = P_BOOL;
  1743. X    bool_value = TRUE;
  1744. X    }
  1745. X
  1746. X    /*
  1747. X     * Now search for a complete match of the parameter
  1748. X     * name with either the full or short name in the
  1749. X     * parameter table.
  1750. X     */
  1751. X    for (pp = ¶ms[0]; pp->p_fullname != NULL; pp++) {
  1752. X    if (strcmp(arg, pp->p_fullname) == 0 ||
  1753. X        strcmp(arg, pp->p_shortname) == 0)
  1754. X        break;
  1755. X    }
  1756. X
  1757. X    if (pp->p_fullname == NULL) {        /* no match found */
  1758. X    if (inter) {
  1759. X        show_error(window, "No such parameter");
  1760. X        return(FALSE);
  1761. X    }
  1762. X    }
  1763. X
  1764. X    /*
  1765. X     * Check the passed type is appropriate for the
  1766. X     * parameter's type. If it isn't, winge and return.
  1767. X     */
  1768. X    switch (pp->p_flags & P_TYPE) {
  1769. X    case P_STRING:
  1770. X    case P_LIST:
  1771. X    case P_NUM:
  1772. X    if (settype != P_STRING) {
  1773. X        if (inter) {
  1774. X        show_error(window,
  1775. X            (pp->p_flags & P_STRING) ?
  1776. X            "Invalid set of string parameter"
  1777. X            : (pp->p_flags & P_NUM) ?
  1778. X            "Invalid set of numeric parameter"
  1779. X            : /* else */
  1780. X            "Invalid set of list parameter");
  1781. X        }
  1782. X        return(FALSE);
  1783. X    }
  1784. X    break;
  1785. X
  1786. X    case P_ENUM:
  1787. X    if (settype != P_STRING) {
  1788. X        if (inter) {
  1789. X        enum_usage(window, pp);
  1790. X        }
  1791. X        return(FALSE);
  1792. X    }
  1793. X    break;
  1794. X
  1795. X    case P_BOOL:
  1796. X    if (settype != P_BOOL) {
  1797. X        if (inter) {
  1798. X        show_error(window, "Invalid set of boolean parameter");
  1799. X        }
  1800. X        return(FALSE);
  1801. X    }
  1802. X    }
  1803. X
  1804. X    /*
  1805. X     * Do any type-specific checking, and set up the
  1806. X     * "val" union to contain the (decoded) value.
  1807. X     */
  1808. X    switch (pp->p_flags & P_TYPE) {
  1809. X    case P_NUM:
  1810. X    {
  1811. X    int i;
  1812. X
  1813. X    cp = str_value;
  1814. X    i = strtoi(&cp);
  1815. X    /*
  1816. X     * If there are extra characters after the number,
  1817. X     * don't accept it.
  1818. X     */
  1819. X    if (*cp != '\0') {
  1820. X        if (inter) {
  1821. X        show_error(window, "Invalid numeric parameter");
  1822. X        }
  1823. X        return(FALSE);
  1824. X    }
  1825. X
  1826. X    val.pv_i = i;
  1827. X    break;
  1828. X    }
  1829. X
  1830. X    case P_ENUM:
  1831. X    for (ep = pp->p_elist; *ep != NULL; ep++) {
  1832. X        if (strcmp(*ep, str_value) == 0)
  1833. X        break;
  1834. X    }
  1835. X
  1836. X    if (*ep == NULL) {
  1837. X        if (inter) {
  1838. X        enum_usage(window, pp);
  1839. X        }
  1840. X        return(FALSE);
  1841. X    }
  1842. X
  1843. X    val.pv_i = ep - pp->p_elist;
  1844. X    break;
  1845. X
  1846. X    case P_STRING:
  1847. X    case P_LIST:
  1848. X    val.pv_s = str_value;
  1849. X    break;
  1850. X
  1851. X    case P_BOOL:
  1852. X    val.pv_b = bool_value;
  1853. X    break;
  1854. X    }
  1855. X
  1856. X    /*
  1857. X     * Call the check function if there is one.
  1858. X     */
  1859. X    if (pp->p_func != nofunc && (*pp->p_func)(window, val, inter) == FALSE) {
  1860. X    return(FALSE);
  1861. X    }
  1862. X
  1863. X    /*
  1864. X     * Set the value.
  1865. X     */
  1866. X    switch (pp->p_flags & P_TYPE) {
  1867. X    case P_NUM:
  1868. X    case P_ENUM:
  1869. X    pp->p_value = val.pv_i;
  1870. X    break;
  1871. X
  1872. X    case P_BOOL:
  1873. X    pp->p_value = bool_value;
  1874. X    break;
  1875. X
  1876. X    case P_STRING:
  1877. X    case P_LIST:
  1878. X    set_param(pp - params, str_value);
  1879. X    break;
  1880. X    }
  1881. X    pp->p_flags |= P_CHANGED;
  1882. X
  1883. X    /*
  1884. X     * Check the bounds for numeric parameters here.
  1885. X     * We will have to make this table-driven later.
  1886. X     */
  1887. X    if (Pn(P_tabstop) <= 0 || Pn(P_tabstop) > MAX_TABSTOP) {
  1888. X    if (inter) {
  1889. X        show_error(window, "Invalid tab size specified");
  1890. X    }
  1891. X    set_param(P_tabstop, 8);
  1892. X    return(FALSE);
  1893. X    }
  1894. X
  1895. X    /*
  1896. X     * Got through all the bounds checking, so we're okay.
  1897. X     */
  1898. X    return TRUE;
  1899. X}
  1900. X
  1901. X/*
  1902. X * Internal parameter setting - parameters are not considered
  1903. X * to have been changed unless they are set by the user.
  1904. X *
  1905. X * All types of parameter are handled by this function.
  1906. X * Enumerated types are special, because two arguments
  1907. X * are expected: the first, always present, is the index,
  1908. X * but the second may be either a valid list of strings
  1909. X * a NULL pointer, the latter indicating that the list
  1910. X * of strings is not to be changed.
  1911. X *
  1912. X * The P_LIST type accepts a string argument and converts
  1913. X * it to a vector of strings which is then stored.
  1914. X */
  1915. X/*VARARGS1*/
  1916. Xvoid
  1917. X#ifdef    __STDC__
  1918. X    set_param(int n, ...)
  1919. X#else
  1920. X    set_param(n, va_alist)
  1921. X    int        n;
  1922. X    va_dcl
  1923. X#endif
  1924. X{
  1925. X    va_list        argp;
  1926. X    Param        *pp;
  1927. X    char        *cp;
  1928. X    char        **elist;
  1929. X
  1930. X    pp = ¶ms[n];
  1931. X
  1932. X    VA_START(argp, n);
  1933. X
  1934. X    switch (pp->p_flags & P_TYPE) {
  1935. X    case P_ENUM:
  1936. X    pp->p_value = va_arg(argp, int);
  1937. X
  1938. X    /*
  1939. X     * If the second argument is a non-NULL list of
  1940. X     * strings, set it into the parameter structure.
  1941. X     * Note that this is not dependent on the return
  1942. X     * value from the check function being TRUE,
  1943. X     * since the check cannot be made until the
  1944. X     * array of strings is in place.
  1945. X     */
  1946. X    elist = va_arg(argp, char **);
  1947. X    if (elist != NULL) {
  1948. X        pp->p_elist = elist;
  1949. X    }
  1950. X    break;
  1951. X
  1952. X    case P_BOOL:
  1953. X    case P_NUM:
  1954. X    pp->p_value = va_arg(argp, int);
  1955. X    break;
  1956. X
  1957. X    case P_LIST:
  1958. X    {
  1959. X        int    argc;
  1960. X        char    **argv;
  1961. X
  1962. X        cp = strsave(va_arg(argp, char *));
  1963. X        if (cp == NULL) {
  1964. X        /*
  1965. X         * This is not necessarily a good idea.
  1966. X         */
  1967. X        show_error(curwin, "Can't allocate memory for parameter");
  1968. X        return;
  1969. X        }
  1970. X
  1971. X        makeargv(cp, &argc, &argv, " \t,");
  1972. X        if (argc == 0 || argv == NULL) {
  1973. X        free(cp);
  1974. X        return;
  1975. X        }
  1976. X        if (pp->p_list != NULL) {
  1977. X        if (pp->p_list[0] != NULL) {
  1978. X            free(pp->p_list[0]);
  1979. X        }
  1980. X        free((char *) pp->p_list);
  1981. X        }
  1982. X        pp->p_list = argv;
  1983. X    }
  1984. X    break;
  1985. X
  1986. X    case P_STRING:
  1987. X    cp = strsave(va_arg(argp, char *));
  1988. X    if (cp == NULL) {
  1989. X        /*
  1990. X         * This is not necessarily a good idea.
  1991. X         */
  1992. X        show_error(curwin, "Can't allocate memory for parameter");
  1993. X    } else {
  1994. X        /*
  1995. X         * We always free up the old string, because
  1996. X         * it must have been allocated at some point.
  1997. X         */
  1998. X        if (pp->p_str != NULL) {
  1999. X        free(pp->p_str);
  2000. X        }
  2001. X        pp->p_str = cp;
  2002. X    }
  2003. X    break;
  2004. X    }
  2005. X
  2006. X    va_end(argp);
  2007. X}
  2008. X
  2009. X/*
  2010. X * Display helpful usage message for an enumerated parameter, listing
  2011. X * the legal values for it.
  2012. X */
  2013. Xstatic void
  2014. Xenum_usage(w, pp)
  2015. X    Xviwin        *w;
  2016. X    Param        *pp;
  2017. X{
  2018. X    Flexbuf        s;
  2019. X    char        **sp;
  2020. X
  2021. X    flexnew(&s);
  2022. X    (void) lformat(&s, "Must be one of:");
  2023. X    for (sp = (char **) pp->p_str; *sp != NULL; sp++) {
  2024. X    (void) lformat(&s, " %s", *sp);
  2025. X    }
  2026. X    show_error(w, "%s", flexgetstr(&s));
  2027. X    flexdelete(&s);
  2028. X}
  2029. X
  2030. X/*
  2031. X * Return a string representation for a single parameter.
  2032. X */
  2033. Xstatic char *
  2034. Xparmstring(pp, leading)
  2035. XParam    *pp;            /* parameter */
  2036. Xint    leading;        /* number of leading spaces in string */
  2037. X{
  2038. X    static Flexbuf    b;
  2039. X
  2040. X    flexclear(&b);
  2041. X    while (leading-- > 0) {
  2042. X    (void) flexaddch(&b, ' ');
  2043. X    }
  2044. X    switch (pp->p_flags & P_TYPE) {
  2045. X    case P_BOOL:
  2046. X    (void) lformat(&b, "%s%s", (pp->p_value ? "" : "no"), pp->p_fullname);
  2047. X    break;
  2048. X
  2049. X    case P_NUM:
  2050. X    (void) lformat(&b, "%s=%d", pp->p_fullname, pp->p_value);
  2051. X    break;
  2052. X
  2053. X    case P_ENUM:
  2054. X    {
  2055. X    int    n;
  2056. X    char    *estr;
  2057. X
  2058. X    for (n = 0; ; n++) {
  2059. X        if ((estr = ((char **) pp->p_str)[n]) == NULL) {
  2060. X        estr = "INTERNAL ERROR";
  2061. X        break;
  2062. X        }
  2063. X        if (n == pp->p_value)
  2064. X        break;
  2065. X    }
  2066. X    (void) lformat(&b, "%s=%s", pp->p_fullname, estr);
  2067. X    break;
  2068. X    }
  2069. X
  2070. X    case P_STRING:
  2071. X    (void) lformat(&b, "%s=%s", pp->p_fullname,
  2072. X                    (pp->p_str != NULL) ? pp->p_str : "");
  2073. X    break;
  2074. X
  2075. X    case P_LIST:
  2076. X    {
  2077. X        register char    **cpp;
  2078. X
  2079. X        (void) lformat(&b, "%s=%s", pp->p_fullname, pp->p_list[0]);
  2080. X        for (cpp = pp->p_list + 1; *cpp != NULL; cpp++) {
  2081. X        (void) lformat(&b, " %s", *cpp);
  2082. X        }
  2083. X    }
  2084. X    break;
  2085. X    }
  2086. X    return(flexgetstr(&b));
  2087. X}
  2088. X
  2089. Xstatic char *
  2090. Xpar_show()
  2091. X{
  2092. X    static bool_t    started = FALSE;
  2093. X
  2094. X    if (!started) {
  2095. X    started = TRUE;
  2096. X    return("Parameters:");
  2097. X    }
  2098. X
  2099. X    for ( ; curparam->p_fullname != NULL; curparam++) {
  2100. X
  2101. X    /*
  2102. X     * Ignore unimplemented parameters.
  2103. X     */
  2104. X    if (curparam->p_func != PFUNCADDR(not_imp)) {
  2105. X        /*
  2106. X         * Display all parameters if show_all is set;
  2107. X         * otherwise, just display changed parameters.
  2108. X         */
  2109. X        if (show_all || (curparam->p_flags & P_CHANGED) != 0) {
  2110. X        break;
  2111. X        }
  2112. X    }
  2113. X    }
  2114. X
  2115. X    if (curparam->p_fullname == NULL) {
  2116. X    started = FALSE;        /* reset for next time */
  2117. X    return(NULL);
  2118. X    } else {
  2119. X    char    *retval;
  2120. X
  2121. X    retval = parmstring(curparam, 3);
  2122. X    curparam++;
  2123. X    return(retval);
  2124. X    }
  2125. X}
  2126. X
  2127. X/*ARGSUSED*/
  2128. Xstatic bool_t
  2129. Xnot_imp(window, new_value, interactive)
  2130. XXviwin        *window;
  2131. XParamval    new_value;
  2132. Xbool_t        interactive;
  2133. X{
  2134. X    if (interactive) {
  2135. X    show_message(window, "That parameter is not implemented!");
  2136. X    }
  2137. X    return(TRUE);
  2138. X}
  2139. X
  2140. X/*ARGSUSED*/
  2141. Xstatic bool_t
  2142. Xset_magic(window, new_value, interactive)
  2143. XXviwin            *window;
  2144. XParamval        new_value;
  2145. Xbool_t            interactive;
  2146. X{
  2147. X    static int    prev_rt = rt_GREP;
  2148. X
  2149. X    if (new_value.pv_b) {
  2150. X    /*
  2151. X     * Turn magic on.
  2152. X     */
  2153. X    if (Pn(P_regextype) == rt_TAGS) {
  2154. X        set_param(P_regextype, prev_rt, (char **) NULL);
  2155. X    }
  2156. X    } else {
  2157. X    /*
  2158. X     * Turn magic off.
  2159. X     */
  2160. X    if (Pn(P_regextype) != rt_TAGS) {
  2161. X        prev_rt = Pn(P_regextype);
  2162. X        set_param(P_regextype, rt_TAGS, (char **) NULL);
  2163. X    }
  2164. X    }
  2165. X    return(TRUE);
  2166. X}
  2167. X
  2168. X/*ARGSUSED*/
  2169. Xstatic bool_t
  2170. Xset_rt(window, new_value, interactive)
  2171. XXviwin        *window;
  2172. XParamval    new_value;
  2173. Xbool_t        interactive;
  2174. X{
  2175. X    switch (new_value.pv_i) {
  2176. X    case rt_TAGS:
  2177. X    case rt_GREP:
  2178. X    case rt_EGREP:
  2179. X    set_param(P_magic, (new_value.pv_i != rt_TAGS));
  2180. X    return(TRUE);
  2181. X    default:
  2182. X    return(FALSE);
  2183. X    }
  2184. X}
  2185. END_OF_FILE
  2186.   if test 23114 -ne `wc -c <'xvi/src/param.c'`; then
  2187.     echo shar: \"'xvi/src/param.c'\" unpacked with wrong size!
  2188.   fi
  2189.   # end of 'xvi/src/param.c'
  2190. fi
  2191. if test -f 'xvi/src/regexp.h' -a "${1}" != "-c" ; then 
  2192.   echo shar: Will not clobber existing file \"'xvi/src/regexp.h'\"
  2193. else
  2194.   echo shar: Extracting \"'xvi/src/regexp.h'\" \(1300 characters\)
  2195.   sed "s/^X//" >'xvi/src/regexp.h' <<'END_OF_FILE'
  2196. X/***
  2197. X
  2198. X* @(#)regexp.h    2.1 7/29/92
  2199. X
  2200. X* program name:
  2201. X    xvi
  2202. X* function:
  2203. X    PD version of UNIX "vi" editor, with extensions.
  2204. X* module name:
  2205. X    regexp.h
  2206. X* module function:
  2207. X    Definitions for regular expression routines.
  2208. X
  2209. X* history:
  2210. X    Regular expression routines by Henry Spencer.
  2211. X    Modfied for use with STEVIE (ST Editor for VI Enthusiasts,
  2212. X     Version 3.10) by Tony Andrews.
  2213. X    Adapted for use with Xvi by Chris & John Downey.
  2214. X    Original copyright notice is in regexp.c.
  2215. X    Please note that this is a modified version.
  2216. X***/
  2217. X
  2218. X/*
  2219. X * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
  2220. X * not the System V one.
  2221. X */
  2222. X
  2223. X#define NSUBEXP 10
  2224. Xtypedef struct regexp {
  2225. X    char    *startp[NSUBEXP];
  2226. X    char    *endp[NSUBEXP];
  2227. X    char    regstart;        /* Internal use only. */
  2228. X    char    reganch;        /* Internal use only. */
  2229. X    char    *regmust;        /* Internal use only. */
  2230. X    int     regmlen;        /* Internal use only. */
  2231. X    char    program[1];        /* Unwarranted chumminess with compiler. */
  2232. X} regexp;
  2233. X
  2234. X#ifndef P
  2235. X#   include "xvi.h"
  2236. X#endif
  2237. X
  2238. X/* regerror.c */
  2239. Xextern    void    regerror P((char *s));
  2240. X
  2241. X/* regexp.c */
  2242. Xextern    regexp    *regcomp P((char *exp));
  2243. Xextern    int    regexec P((regexp *prog, char *string, int at_bol));
  2244. X
  2245. X/* regsub.c */
  2246. Xextern void    regsub P((regexp *prog, char *source, char *dest));
  2247. END_OF_FILE
  2248.   if test 1300 -ne `wc -c <'xvi/src/regexp.h'`; then
  2249.     echo shar: \"'xvi/src/regexp.h'\" unpacked with wrong size!
  2250.   fi
  2251.   # end of 'xvi/src/regexp.h'
  2252. fi
  2253. echo shar: End of archive 9 \(of 18\).
  2254. cp /dev/null ark9isdone
  2255. MISSING=""
  2256. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do
  2257.     if test ! -f ark${I}isdone ; then
  2258.     MISSING="${MISSING} ${I}"
  2259.     fi
  2260. done
  2261. if test "${MISSING}" = "" ; then
  2262.     echo You have unpacked all 18 archives.
  2263.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2264. else
  2265.     echo You still must unpack the following archives:
  2266.     echo "        " ${MISSING}
  2267. fi
  2268. exit 0
  2269. exit 0 # Just in case...
  2270.