home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / util / vim-2.0.lha / Vim-2.0 / src / cmdline.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-15  |  58.8 KB  |  2,921 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved
  4.  *
  5.  * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  6.  *                            Tim Thompson            twitch!tjt
  7.  *                            Tony Andrews            onecom!wldrdg!tony 
  8.  *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  9.  */
  10.  
  11. /*
  12.  * cmdline.c: functions for reading in the command line and executing it
  13.  */
  14.  
  15. #include "vim.h"
  16. #include "globals.h"
  17. #include "proto.h"
  18. #include "param.h"
  19. #include "cmdtab.h"
  20. #include "ops.h"            /* included because we call functions in ops.c */
  21. #include "fcntl.h"            /* for chdir() */
  22.  
  23. #ifdef LATTICE
  24. # define mktemp(a)    tmpnam(a)
  25. #endif
  26.  
  27. /*
  28.  * the history list of alternate files
  29.  */
  30. #define NUMALTFILES 20
  31.  
  32. static char    *altfiles[NUMALTFILES];    /* alternate files */
  33. static char    *saltfiles[NUMALTFILES];    /* alternate files without path */
  34. static linenr_t altlnum[NUMALTFILES];    /* line # in alternate file */
  35. static linenr_t doecmdlnum = 0;            /* line # in new file for doecmd() */
  36.  
  37. /*
  38.  * variables shared between getcmdline() and redrawcmdline()
  39.  */
  40. static int         cmdlen;        /* number of chars on command line */
  41. static int         cmdpos;        /* current cursor position */
  42. static int         cmdslen;        /* lenght of command line on screen */
  43. static int         cmdspos;        /* cursor position on screen */
  44. static int         cmdfirstc;     /* ':', '/' or '?' */
  45. static u_char    *cmdbuff;        /* pointer to command line buffer */
  46.  
  47. /*
  48.  * The next two variables contain the bounds of any range given in a command.
  49.  * They are set by docmdline().
  50.  */
  51. static linenr_t     line1, line2;
  52.  
  53. static int            forceit;
  54. static int            regname;
  55. static int            quitmore = 0;
  56. static int          cmd_numfiles = -1;      /* number of files found by
  57.                                                     filename completion */
  58.  
  59. static void        putcmdline __ARGS((int, u_char *));
  60. static void        cmdchecklen __ARGS((void));
  61. static void        cursorcmd __ARGS((void));
  62. static int        ccheck_abbr __ARGS((int));
  63. static u_char    *DoOneCmd __ARGS((u_char *));
  64. static void        dobang __ARGS((int, u_char *));
  65. static int        autowrite __ARGS((void));
  66. static int        dowrite __ARGS((u_char *, int));
  67. static int        doecmd __ARGS((char *, char *));
  68. static void        doshell __ARGS((char *));
  69. static void        dofilter __ARGS((u_char *, int, int));
  70. static void        domake __ARGS((char *));
  71. static int        doarglist __ARGS((char *));
  72. static int        check_readonly __ARGS((void));
  73. static int        check_changed __ARGS((int));
  74. static int        check_more __ARGS((int));
  75. static void        setaltfname __ARGS((char *, char *, linenr_t, int));
  76. static void        nextwild __ARGS((u_char *, int));
  77. static void        showmatches __ARGS((char *, int));
  78. static char        *addstar __ARGS((char *, int));
  79. static linenr_t get_address __ARGS((u_char **));
  80. static void        do_align __ARGS((linenr_t, linenr_t, int, int));
  81.  
  82. extern char        *mktemp __ARGS((char *));
  83.  
  84. extern int global_busy, global_wait;    /* shared with csearch.c, message.c */
  85.  
  86. /*
  87.  * getcmdline() - accept a command line starting with ':', '!', '/', or '?'
  88.  *
  89.  * For searches the optional matching '?' or '/' is removed.
  90.  */
  91.  
  92.     int
  93. getcmdline(firstc, buff)
  94.     int            firstc;     /* either ':', '/', or '?' */
  95.     u_char        *buff;         /* buffer for command string */
  96. {
  97.     register u_char     c;
  98.              int        nextc = 0;
  99.     register int        i;
  100.              int        retval;
  101.              int        hiscnt;                /* current history line in use */
  102.     static     char         **history = NULL;    /* history table */
  103.     static     int        hislen = 0;         /* actual lengt of history table */
  104.              int        newlen;                /* new length of history table */
  105.     static     int        hisidx = -1;        /* last entered entry */
  106.              char        **temp;
  107.              char        *lookfor = NULL;    /* string to match */
  108.              int        j = -1;
  109.              int        gotesc = FALSE;        /* TRUE when last char typed was <ESC> */
  110.  
  111. /*
  112.  * set some variables for redrawcmd()
  113.  */
  114.     cmdfirstc = firstc;
  115.     cmdbuff = buff;
  116.     cmdlen = cmdpos = 0;
  117.     cmdslen = cmdspos = 1;
  118.     State = CMDLINE;
  119.     gotocmdline(TRUE, firstc);
  120.  
  121. /*
  122.  * if size of history table changed, reallocate it
  123.  */
  124.     newlen = (int)p_hi;
  125.     if (newlen != hislen)                        /* history length changed */
  126.     {
  127.         if (newlen)
  128.             temp = (char **)lalloc((u_long)(newlen * sizeof(char *)), TRUE);
  129.         else
  130.             temp = NULL;
  131.         if (newlen == 0 || temp != NULL)
  132.         {
  133.             if (newlen > hislen)            /* array becomes bigger */
  134.             {
  135.                 for (i = 0; i <= hisidx; ++i)
  136.                     temp[i] = history[i];
  137.                 j = i;
  138.                 for ( ; i <= newlen - (hislen - hisidx); ++i)
  139.                     temp[i] = NULL;
  140.                 for ( ; j < hislen; ++i, ++j)
  141.                     temp[i] = history[j];
  142.             }
  143.             else                            /* array becomes smaller */
  144.             {
  145.                 j = hisidx;
  146.                 for (i = newlen - 1; ; --i)
  147.                 {
  148.                     if (i >= 0)
  149.                         temp[i] = history[j];    /* copy newest entries */
  150.                     else
  151.                         free(history[j]);        /* remove older entries */
  152.                     if (--j < 0)
  153.                         j = hislen - 1;
  154.                     if (j == hisidx)
  155.                         break;
  156.                 }
  157.                 hisidx = newlen - 1;
  158.             }
  159.             free(history);
  160.             history = temp;
  161.             hislen = newlen;
  162.         }
  163.     }
  164.     hiscnt = hislen;            /* set hiscnt to impossible history value */
  165.  
  166. #ifdef DIGRAPHS
  167.     dodigraph(-1);                /* init digraph typahead */
  168. #endif
  169.  
  170.     /* collect the command string, handling '\b', @ and much more */
  171.     for (;;)
  172.     {
  173.         cursorcmd();    /* set the cursor on the right spot */
  174.         if (nextc)        /* character remaining from CTRL-V */
  175.         {
  176.             c = nextc;
  177.             nextc = 0;
  178.         }
  179.         else
  180.         {
  181.             c = vgetc();
  182.             if (c == Ctrl('C') && got_int)
  183.                 got_int = FALSE;
  184.         }
  185.  
  186.         if (lookfor && c != K_SDARROW && c != K_SUARROW)
  187.         {
  188.             free(lookfor);
  189.             lookfor = NULL;
  190.         }
  191.  
  192.         if (cmd_numfiles > 0 && !(c == p_wc && KeyTyped) && c != Ctrl('N') &&
  193.                         c != Ctrl('P') && c != Ctrl('A') && c != Ctrl('L'))
  194.             (void)ExpandOne(NULL, FALSE, -2);    /* may free expanded file names */
  195.  
  196. #ifdef DIGRAPHS
  197.         c = dodigraph(c);
  198. #endif
  199.  
  200.         if (c == '\n' || c == '\r' || (c == ESC && !KeyTyped))
  201.         {
  202.             if (ccheck_abbr(c + 0x100))
  203.                 continue;
  204.             outchar('\r');
  205.             flushbuf();
  206.             break;
  207.         }
  208.  
  209.             /* hitting <ESC> twice means: abandon command line */
  210.             /* wildcard expansion is only done when the key is really typed, not
  211.                when it comes from a macro */
  212.         if (c == p_wc && !gotesc && KeyTyped)
  213.         {
  214.             if (cmd_numfiles > 0)    /* typed p_wc twice */
  215.                 nextwild(buff, 3);
  216.             else                    /* typed p_wc first time */
  217.                 nextwild(buff, 0);
  218.             if (c == ESC)
  219.                 gotesc = TRUE;
  220.             continue;
  221.         }
  222.         gotesc = FALSE;
  223.  
  224.         if (c == K_ZERO)        /* NUL is stored as NL */
  225.             c = '\n';
  226.  
  227.         switch (c)
  228.         {
  229.         case BS:
  230.         case DEL:
  231.         case Ctrl('W'):
  232.                 /*
  233.                  * delete current character is the same as backspace on next
  234.                  * character, except at end of line
  235.                  */
  236.                 if (c == DEL && cmdpos != cmdlen)
  237.                     ++cmdpos;
  238.                 if (cmdpos > 0)
  239.                 {
  240.                     j = cmdpos;
  241.                     if (c == Ctrl('W'))
  242.                     {
  243.                         while (cmdpos && isspace(buff[cmdpos - 1]))
  244.                             --cmdpos;
  245.                         i = isidchar(buff[cmdpos - 1]);
  246.                         while (cmdpos && !isspace(buff[cmdpos - 1]) && isidchar(buff[cmdpos - 1]) == i)
  247.                             --cmdpos;
  248.                     }
  249.                     else
  250.                         --cmdpos;
  251.                     cmdlen -= j - cmdpos;
  252.                     i = cmdpos;
  253.                     while (i < cmdlen)
  254.                         buff[i++] = buff[j++];
  255.                     redrawcmd();
  256.                 }
  257.                 else if (cmdlen == 0 && c != Ctrl('W'))
  258.                 {
  259.                     retval = FALSE;
  260.                     msg("");
  261.                     goto returncmd;     /* back to cmd mode */
  262.                 }
  263.                 continue;
  264.  
  265. /*        case '@':    only in very old vi */
  266.         case Ctrl('U'):
  267. clearline:
  268.                 cmdpos = 0;
  269.                 cmdlen = 0;
  270.                 cmdslen = 1;
  271.                 cmdspos = 1;
  272.                 redrawcmd();
  273.                 continue;
  274.  
  275.         case ESC:            /* get here if p_wc != ESC or when ESC typed twice */
  276.         case Ctrl('C'):
  277.                 retval = FALSE;
  278.                 msg("");
  279.                 goto returncmd;     /* back to cmd mode */
  280.  
  281.         case Ctrl('D'):
  282.             {
  283.                 for (i = cmdpos; i > 0 && buff[i - 1] != ' '; --i)
  284.                         ;
  285.                 showmatches((char *)&buff[i], cmdpos - i);
  286.                 for (i = Rows_max - Rows; i; --i)
  287.                     outchar('\n');
  288.  
  289.                 redrawcmd();
  290.                 continue;
  291.             }
  292.  
  293.         case K_RARROW:
  294.         case K_SRARROW:
  295.                 do
  296.                 {
  297.                         if (cmdpos >= cmdlen)
  298.                                 break;
  299.                         cmdspos += charsize(buff[cmdpos]);
  300.                         ++cmdpos;
  301.                 }
  302.                 while (c == K_SRARROW && buff[cmdpos] != ' ');
  303.                 continue;
  304.  
  305.         case K_LARROW:
  306.         case K_SLARROW:
  307.                 do
  308.                 {
  309.                         if (cmdpos <= 0)
  310.                                 break;
  311.                         --cmdpos;
  312.                         cmdspos -= charsize(buff[cmdpos]);
  313.                 }
  314.                 while (c == K_SLARROW && buff[cmdpos - 1] != ' ');
  315.                 continue;
  316.  
  317.         case Ctrl('B'):        /* begin of command line */
  318.                 cmdpos = 0;
  319.                 cmdspos = 1;
  320.                 continue;
  321.  
  322.         case Ctrl('E'):        /* end of command line */
  323.                 cmdpos = cmdlen;
  324.                 buff[cmdlen] = NUL;
  325.                 cmdspos = strsize((char *)buff) + 1;
  326.                 continue;
  327.  
  328.         case Ctrl('A'):        /* all matches */
  329.                 nextwild(buff, 4);
  330.                 continue;
  331.  
  332.         case Ctrl('L'):        /* longest common part */
  333.                 nextwild(buff, 5);
  334.                 continue;
  335.  
  336.         case Ctrl('N'):        /* next match */
  337.         case Ctrl('P'):        /* previous match */
  338.                 if (cmd_numfiles > 0)
  339.                 {
  340.                     nextwild(buff, (c == Ctrl('P')) ? 2 : 1);
  341.                     continue;
  342.                 }
  343.  
  344.         case K_UARROW:
  345.         case K_DARROW:
  346.         case K_SUARROW:
  347.         case K_SDARROW:
  348.                 if (hislen == 0)        /* no history */
  349.                     continue;
  350.  
  351.                 i = hiscnt;
  352.             
  353.                     /* save current command string */
  354.                 if (c == K_SUARROW || c == K_SDARROW)
  355.                 {
  356.                     buff[cmdpos] = NUL;
  357.                     if (lookfor == NULL && (lookfor = strsave((char *)buff)) == NULL)
  358.                         continue;
  359.  
  360.                     j = strlen(lookfor);
  361.                 }
  362.                 for (;;)
  363.                 {
  364.                         /* one step backwards */
  365.                     if (c == K_UARROW || c == K_SUARROW || c == Ctrl('P'))
  366.                     {
  367.                         if (hiscnt == hislen)    /* first time */
  368.                             hiscnt = hisidx;
  369.                         else if (hiscnt == 0 && hisidx != hislen - 1)
  370.                             hiscnt = hislen - 1;
  371.                         else if (hiscnt != hisidx + 1)
  372.                             --hiscnt;
  373.                         else                    /* at top of list */
  374.                             break;
  375.                     }
  376.                     else    /* one step forwards */
  377.                     {
  378.                         if (hiscnt == hisidx)    /* on last entry, clear the line */
  379.                         {
  380.                             hiscnt = hislen;
  381.                             goto clearline;
  382.                         }
  383.                         if (hiscnt == hislen)    /* not on a history line, nothing to do */
  384.                             break;
  385.                         if (hiscnt == hislen - 1)    /* wrap around */
  386.                             hiscnt = 0;
  387.                         else
  388.                             ++hiscnt;
  389.                     }
  390.                     if (hiscnt < 0 || history[hiscnt] == NULL)
  391.                     {
  392.                         hiscnt = i;
  393.                         break;
  394.                     }
  395.                     if ((c != K_SUARROW && c != K_SDARROW) || hiscnt == i ||
  396.                             strncmp(history[hiscnt], lookfor, (size_t)j) == 0)
  397.                         break;
  398.                 }
  399.  
  400.                 if (hiscnt != i)        /* jumped to other entry */
  401.                 {
  402.                     strcpy((char *)buff, history[hiscnt]);
  403.                     cmdpos = cmdlen = strlen((char *)buff);
  404.                     redrawcmd();
  405.                 }
  406.                 continue;
  407.  
  408.         case Ctrl('V'):
  409.                 putcmdline('^', buff);
  410.                 c = get_literal(&nextc);    /* get next (two) character(s) */
  411.                 break;
  412.  
  413. #ifdef DIGRAPHS
  414.         case Ctrl('K'):
  415.                 putcmdline('?', buff);
  416.                   c = vgetc();
  417.                 putcmdline(c, buff);
  418.                 c = getdigraph(c, vgetc());
  419.                 break;
  420. #endif /* DIGRAPHS */
  421.         }
  422.  
  423.         /* we come here if we have a normal character */
  424.  
  425.         if (!isidchar(c) && ccheck_abbr(c))
  426.             continue;
  427.  
  428.         if (cmdlen < CMDBUFFSIZE - 2)
  429.         {
  430.                 for (i = cmdlen++; i > cmdpos; --i)
  431.                         buff[i] = buff[i - 1];
  432.                 buff[cmdpos] = c;
  433.                 outtrans((char *)(buff + cmdpos), cmdlen - cmdpos);
  434.                 ++cmdpos;
  435.                 i = charsize(c);
  436.                 cmdslen += i;
  437.                 cmdspos += i;
  438.         }
  439.         cmdchecklen();
  440.     }
  441.     retval = TRUE;                /* when we get here we have a valid command line */
  442.  
  443. returncmd:
  444.     buff[cmdlen] = NUL;
  445.     if (hislen != 0 && cmdlen != 0)        /* put line in history buffer */
  446.     {
  447.         if (++hisidx == hislen)
  448.             hisidx = 0;
  449.         free(history[hisidx]);
  450.         history[hisidx] = strsave((char *)buff);
  451.     }
  452.  
  453.     /*
  454.      * If the screen was shifted up, redraw the whole screen (later).
  455.      * If the line is too long, clear it, so ruler and shown command do
  456.      * not get printed in the middle of it.
  457.      */
  458.     if (cmdoffset)
  459.         must_redraw = CLEAR;
  460.     else if (cmdslen >= sc_col)
  461.         gotocmdline(TRUE, NUL);
  462.     State = NORMAL;
  463.     script_winsize_pp();
  464.     return retval;
  465. }
  466.  
  467. /*
  468.  * put a character on the command line.
  469.  * Used for CTRL-V and CTRL-K
  470.  */
  471.     static void
  472. putcmdline(c, buff)
  473.     int        c;
  474.     u_char    *buff;
  475. {
  476.     int        len;
  477.     char    buf[2];
  478.  
  479.     buf[0] = c;
  480.     buf[1] = 0;
  481.     len = outtrans(buf, 1);
  482.     outtrans((char *)(buff + cmdpos), cmdlen - cmdpos);
  483.     cmdslen += len;
  484.     cmdchecklen();
  485.     cmdslen -= len;
  486.     cursorcmd();
  487. }
  488.  
  489. /*
  490.  * Check if the command line spans more than one screen line.
  491.  * The maximum number of lines is remembered.
  492.  */
  493.     static void
  494. cmdchecklen()
  495. {
  496.     if (cmdslen / (int)Columns > cmdoffset)
  497.         cmdoffset = cmdslen / (int)Columns;
  498. }
  499.  
  500. /*
  501.  * this fuction is called when the screen size changes
  502.  */
  503.     void
  504. redrawcmdline()
  505. {
  506.         cmdoffset = 0;
  507.         redrawcmd();
  508.         cursorcmd();
  509. }
  510.  
  511. /*
  512.  * Redraw what is currently on the command line.
  513.  */
  514.     void
  515. redrawcmd()
  516. {
  517.     register int i;
  518.  
  519.     windgoto((int)Rows - 1 - cmdoffset, 0);
  520.     outchar(cmdfirstc);
  521.     cmdslen = 1;
  522.     cmdspos = 1;
  523.     outtrans((char *)cmdbuff, cmdlen);
  524.     for (i = 0; i < cmdlen; )
  525.     {
  526.         cmdslen += charsize(cmdbuff[i]);
  527.         if (++i == cmdpos)
  528.                 cmdspos = cmdslen;
  529.     }
  530.     for (i = (cmdoffset + 1) * (int)Columns - cmdslen; --i > 0; )
  531.         outchar(' ');
  532.     cmdchecklen();
  533. }
  534.  
  535.     static void
  536. cursorcmd()
  537. {
  538.     windgoto((int)Rows - 1 - cmdoffset + (cmdspos / (int)Columns), cmdspos % (int)Columns);
  539. }
  540.  
  541. /*
  542.  * Check the word in front of the cursor for an abbreviation.
  543.  * Called when the non-id character "c" has been entered.
  544.  * When an abbreviation is recognized it is removed from the text with
  545.  * backspaces and the replacement string is inserted, followed by "c".
  546.  */
  547.     static int
  548. ccheck_abbr(c)
  549.     int c;
  550. {
  551.     if (p_paste || no_abbr)            /* no abbreviations or in paste mode */
  552.         return FALSE;
  553.     
  554.     return check_abbr(c, (char *)cmdbuff, cmdpos, 0);
  555. }
  556.  
  557. /*
  558.  * docmdline(): execute an Ex command line
  559.  *
  560.  * 1. If no line given, get one.
  561.  * 2. Split up in parts separated with '|'.
  562.  *
  563.  * This function may be called recursively!
  564.  */
  565.     void
  566. docmdline(cmdline)
  567.     u_char        *cmdline;
  568. {
  569.     u_char        buff[CMDBUFFSIZE];        /* command line */
  570.     u_char        *nextcomm;
  571.  
  572. /*
  573.  * 1. If no line given: get one.
  574.  */
  575.     if (cmdline == NULL)
  576.     {
  577.         if (!getcmdline(':', buff))
  578.             return;
  579.     }
  580.     else
  581.     {
  582.         if (strlen((char *)cmdline) > (size_t)(CMDBUFFSIZE - 2))
  583.         {
  584.             emsg(e_toolong);
  585.             return;
  586.         }
  587.         /* Make a copy of the command so we can mess with it. */
  588.         strcpy((char *)buff, (char *)cmdline);
  589.     }
  590.  
  591. /*
  592.  * 2. Loop for each '|' separated command.
  593.  *    DoOneCmd will set nextcommand to NULL if there is no trailing '|'.
  594.  */
  595.     for (;;)
  596.     {
  597.         nextcomm = DoOneCmd(buff);
  598.         if (nextcomm == NULL)
  599.             break;
  600.         strcpy((char *)buff, (char *)nextcomm);
  601.     }
  602. }
  603.  
  604. /*
  605.  * Execute one Ex command.
  606.  *
  607.  * 2. skip comment lines and leading space
  608.  * 3. parse range
  609.  * 4. parse command
  610.  * 5. parse arguments
  611.  * 6. switch on command name
  612.  *
  613.  * This function may be called recursively!
  614.  */
  615.     static u_char *
  616. DoOneCmd(buff)
  617.     u_char *buff;
  618. {
  619.     u_char                cmdbuf[CMDBUFFSIZE];    /* for '%' and '#' expansion */
  620.     u_char                c;
  621.     register u_char        *p;
  622.     char                *q;
  623.     u_char                *cmd, *arg;
  624.     int                 i;
  625.     int                    cmdidx;
  626.     int                    argt;
  627.     register linenr_t    lnum;
  628.     long                n;
  629.     int                    addr_count;    /* number of address specifications */
  630.     FPOS                pos;
  631.     int                    append = FALSE;            /* write with append */
  632.     int                    usefilter = FALSE;        /* filter instead of file name */
  633.     u_char                *nextcomm;
  634.  
  635.     if (quitmore)
  636.         --quitmore;        /* when not editing the last file :q has to be typed twice */
  637. /*
  638.  * 2. skip comment lines and leading space, colons or bars
  639.  */
  640.     for (cmd = buff; *cmd && strchr(" \t:|", *cmd) != NULL; cmd++)
  641.         ;
  642.  
  643.     nextcomm = NULL;        /* default: no next command */
  644.     if (strchr("#\"", *cmd) != NULL)    /* ignore comment and empty lines */
  645.         goto doend;
  646.  
  647. /*
  648.  * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
  649.  *
  650.  * where 'addr' is:
  651.  *
  652.  * %          (entire file)
  653.  * $  [+-NUM]
  654.  * 'x [+-NUM] (where x denotes a currently defined mark)
  655.  * .  [+-NUM]
  656.  * [+-NUM]..
  657.  * NUM
  658.  *
  659.  * The cmd pointer is updated to point to the first character following the
  660.  * range spec. If an initial address is found, but no second, the upper bound
  661.  * is equal to the lower.
  662.  */
  663.  
  664.     addr_count = 0;
  665.     --cmd;
  666.     do
  667.     {
  668.         ++cmd;                            /* skip ',' or ';' */
  669.         line1 = line2;
  670.         line2 = Curpos.lnum;            /* default is current line number */
  671.         skipspace((char **)&cmd);
  672.         lnum = get_address(&cmd);
  673.         if (lnum == INVLNUM)
  674.         {
  675.             if (*cmd == '%')            /* '%' - all lines */
  676.             {
  677.                 ++cmd;
  678.                 line1 = 1;
  679.                 line2 = line_count;
  680.                 ++addr_count;
  681.             }
  682.         }
  683.         else
  684.             line2 = lnum;
  685.         addr_count++;
  686.  
  687.         if (*cmd == ';')
  688.         {
  689.             if (line2 == 0)
  690.                 Curpos.lnum = 1;
  691.             else
  692.                 Curpos.lnum = line2;
  693.         }
  694.     } while (*cmd == ',' || *cmd == ';');
  695.  
  696.     /* One address given: set start and end lines */
  697.     if (addr_count == 1)
  698.     {
  699.         line1 = line2;
  700.             /* ... but only implicit: really no address given */
  701.         if (lnum == INVLNUM)
  702.             addr_count = 0;
  703.     }
  704.  
  705.     if (line1 > line2 || line2 > line_count)
  706.     {
  707.         emsg(e_invrange);
  708.         goto doend;
  709.     }
  710.  
  711. /*
  712.  * 4. parse command
  713.  */
  714.  
  715.     skipspace((char **)&cmd);
  716.  
  717.     /*
  718.      * If we got a line, but no command, then go to the line.
  719.      */
  720.     if (*cmd == NUL || *cmd == '"' || (*cmd == '|' && (nextcomm = cmd) != NULL))
  721.     {
  722.         if (addr_count != 0)
  723.         {
  724.             if (line2 == 0)
  725.                 Curpos.lnum = 1;
  726.             else
  727.                 Curpos.lnum = line2;
  728.             Curpos.col = 0;
  729.             cursupdate();
  730.         }
  731.         goto doend;
  732.     }
  733.  
  734.     /*
  735.      * isolate the command and search for it in the command table
  736.      */
  737.     p = cmd;
  738.     if (*cmd != 'k')
  739.         while (isalpha(*p))
  740.             ++p;
  741.     if (p == cmd && strchr("@!=><&k", *p) != NULL)    /* non-alpha or 'k' command */
  742.         ++p;
  743.     i = (int)(p - cmd);
  744.  
  745.     for (cmdidx = 0; cmdidx < CMD_SIZE; ++cmdidx)
  746.         if (strncmp(cmdnames[cmdidx].cmd_name, (char *)cmd, (size_t)i) == 0)
  747.             break;
  748.  
  749.     if (i == 0 || cmdidx == CMD_SIZE)
  750.     {
  751.         emsg(e_invcmd);
  752.         goto doend;
  753.     }
  754.  
  755.     if (*p == '!')                    /* forced commands */
  756.     {
  757.         ++p;
  758.         forceit = TRUE;
  759.     }
  760.     else
  761.         forceit = FALSE;
  762.  
  763. /*
  764.  * 5. parse arguments
  765.  */
  766.     argt = cmdnames[cmdidx].cmd_argt;
  767.  
  768.     if (!(argt & RANGE) && addr_count)
  769.     {
  770.         emsg(e_norange);
  771.         goto doend;
  772.     }
  773.  
  774.     if (!(argt & ZEROR))            /* zero in range not allowed */
  775.     {
  776.         if (line1 == 0)
  777.             line1 = 1;
  778.         if (line2 == 0)
  779.             line2 = 1;
  780.     }
  781.  
  782.     /*
  783.      * for the :make command we insert the 'makeprg' option here,
  784.      * so things like % get expanded
  785.      */
  786.     if (cmdidx == CMD_make)
  787.     {
  788.         if (strlen(p_mp) + strlen((char *)p) + 2 >= (unsigned)CMDBUFFSIZE)
  789.         {
  790.             emsg(e_toolong);
  791.             goto doend;
  792.         }
  793.         strcpy((char *)cmdbuf, p_mp);
  794.         strcat((char *)cmdbuf, " ");
  795.         strcat((char *)cmdbuf, (char *)p);
  796.         strcpy((char *)buff, (char *)cmdbuf);
  797.         p = buff;
  798.     }
  799.  
  800.     arg = p;                        /* remember start of argument */
  801.     skipspace((char **)&arg);
  802.  
  803.     if ((argt & NEEDARG) && *arg == NUL)
  804.     {
  805.         emsg(e_argreq);
  806.         goto doend;
  807.     }
  808.  
  809.     /*
  810.      * check for '|' to separate commands and '"' to start comments
  811.      */
  812.     if (argt & TRLBAR)
  813.     {
  814.         while (*p)
  815.         {
  816.             if (*p == Ctrl('V'))
  817.             {
  818.                 if (argt & USECTRLV)    /* skip the CTRL-V and next char */
  819.                     ++p;
  820.                 else                    /* remove CTRL-V and skip next char */
  821.                     strcpy((char *)p, (char *)p + 1);
  822.             }
  823.             else if ((*p == '"' && !(argt & NOTRLCOM)) || *p == '|')
  824.             {
  825.                 if (*(p - 1) == '\\')    /* remove the backslash */
  826.                 {
  827.                     strcpy((char *)p - 1, (char *)p);
  828.                     --p;
  829.                 }
  830.                 else
  831.                 {
  832.                     if (*p == '|')
  833.                         nextcomm = p + 1;
  834.                     *p = NUL;
  835.                     break;
  836.                 }
  837.             }
  838.             ++p;
  839.         }
  840.         if (!(argt & NOTRLCOM))            /* remove trailing spaces */
  841.         {
  842.             q = (char *)arg + strlen((char *)arg);
  843.             while (--q > (char *)arg && isspace(q[0]) && q[-1] != '\\' && q[-1] != Ctrl('V'))
  844.                 *q = NUL;
  845.         }
  846.     }
  847.  
  848.     if ((argt & DFLALL) && addr_count == 0)
  849.     {
  850.         line1 = 1;
  851.         line2 = line_count;
  852.     }
  853.  
  854.     regname = 0;
  855.         /* accept numbered register only when no count allowed (:put) */
  856.     if ((argt & REGSTR) && (isalpha(*arg) || *arg == '.' || *arg == '"' || (!(argt & COUNT) && isdigit(*arg))))
  857.     {
  858.         regname = *arg;
  859.         ++arg;
  860.         skipspace((char **)&arg);
  861.     }
  862.  
  863.     if ((argt & COUNT) && isdigit(*arg))
  864.     {
  865.         n = getdigits((char **)&arg);
  866.         skipspace((char **)&arg);
  867.         if (n <= 0)
  868.         {
  869.             emsg(e_zerocount);
  870.             goto doend;
  871.         }
  872.         line1 = line2;
  873.         line2 += n - 1;
  874.     }
  875.  
  876.     if (!(argt & EXTRA) && strchr("|\"#", *arg) == NULL)    /* no arguments allowed */
  877.     {
  878.         emsg(e_trailing);
  879.         goto doend;
  880.     }
  881.  
  882.     if (cmdidx == CMD_write)
  883.     {
  884.         if (*arg == '>')                        /* append */
  885.         {
  886.             if (*++arg != '>')                /* typed wrong */
  887.             {
  888.                 emsg("Use w or w>>");
  889.                 goto doend;
  890.             }
  891.             ++arg;
  892.             skipspace((char **)&arg);
  893.             append = TRUE;
  894.         }
  895.         else if (*arg == '!')                    /* :w !filter */
  896.         {
  897.             ++arg;
  898.             usefilter = TRUE;
  899.         }
  900.     }
  901.  
  902.     if (cmdidx == CMD_read)
  903.     {
  904.         usefilter = forceit;                    /* :r! filter if forceit */
  905.         if (*arg == '!')                        /* :r !filter */
  906.         {
  907.             ++arg;
  908.             usefilter = TRUE;
  909.         }
  910.     }
  911.  
  912.     /*
  913.      * change '%' to Filename, '#' to altfile
  914.      */
  915.     if (argt & XFILE)
  916.     {
  917.         for (p = arg; *p; ++p)
  918.         {
  919.             c = *p;
  920.             if (c != '%' && c != '#')    /* nothing to expand */
  921.                 continue;
  922.             if (*(p - 1) == '\\')        /* remove escaped char */
  923.             {
  924.                 strcpy((char *)p - 1, (char *)p);
  925.                 --p;
  926.                 continue;
  927.             }
  928.  
  929.             n = 1;                /* length of what we expand */
  930.             if (c == '#' && *(p + 1) == '<')
  931.             {                    /* "#<": current file name without extension */
  932.                 n = 2;
  933.                 c = '<';
  934.             }
  935.             if (c == '%' || c == '<')
  936.             {
  937.                 if (check_fname())
  938.                     goto doend;
  939.                 q = xFilename;
  940.             }
  941.             else
  942.             {
  943.                 q = (char *)p + 1;
  944.                 i = (int)getdigits(&q);
  945.                 n = q - (char *)p;
  946.  
  947.                 if (i >= NUMALTFILES || altfiles[i] == NULL)
  948.                 {
  949.                         emsg(e_noalt);
  950.                         goto doend;
  951.                 }
  952.                 doecmdlnum = altlnum[i];
  953.                 if (did_cd)
  954.                     q = altfiles[i];
  955.                 else
  956.                     q = saltfiles[i];
  957.             }
  958.             i = strlen((char *)arg) + strlen(q) + 3;
  959.             if (nextcomm)
  960.                 i += strlen((char *)nextcomm);
  961.             if (i > CMDBUFFSIZE)
  962.             {
  963.                 emsg(e_toolong);
  964.                 goto doend;
  965.             }
  966.             /*
  967.              * we built the new argument in cmdbuf[], then copy it back to buff[]
  968.              */
  969.             *p = NUL;                            /* truncate at the '#' or '%' */
  970.             strcpy((char *)cmdbuf, (char *)arg);/* copy up to there */
  971.             i = p - arg;                        /* remember the lenght */
  972.             strcat((char *)cmdbuf, q);            /* append the file name */
  973.             if (c == '<' && (arg = (u_char *)strrchr(q, '.')) != NULL &&
  974.                             arg >= (u_char *)gettail(q))    /* remove extension */
  975.                 *((char *)cmdbuf + ((char *)arg - q) + i) = NUL;
  976.             i = strlen((char *)cmdbuf);            /* remember the end of the filename */
  977.             strcat((char *)cmdbuf, (char *)p+n);/* append what is after '#' or '%' */
  978.             p = buff + i - 1;                    /* remember where to continue */
  979.             if (nextcomm)                        /* append next command */
  980.             {
  981.                 i = strlen((char *)cmdbuf) + 1;
  982.                 strcpy((char *)cmdbuf + i, (char *)nextcomm);
  983.                 nextcomm = buff + i;
  984.             }
  985.             strcpy((char *)buff, (char *)cmdbuf);/* copy back to buff[] */
  986.             arg = buff;
  987.         }
  988.  
  989.         /*
  990.          * One file argument: expand wildcards.
  991.          * Don't do this with ":r !command" or ":w !command".
  992.          */
  993.         if (argt & NOSPC)
  994.         {
  995.             if (has_wildcard((char *)arg) && !usefilter)
  996.             {
  997.                 if ((p = (u_char *)ExpandOne(arg, TRUE, -1)) == NULL)
  998.                     goto doend;
  999.                 if (strlen((char *)p) + arg - buff < CMDBUFFSIZE - 2)
  1000.                     strcpy((char *)arg, (char *)p);
  1001.                 else
  1002.                     emsg(e_toolong);
  1003.                 free(p);
  1004.             }
  1005.         }
  1006.     }
  1007.  
  1008. /*
  1009.  * 6. switch on command name
  1010.  */
  1011.     switch (cmdidx)
  1012.     {
  1013.         case CMD_quit:
  1014.                 if (!check_more(FALSE))        /* if more files we won't exit */
  1015.                     exiting = TRUE;
  1016.                 if (check_changed(FALSE) || check_more(TRUE))
  1017.                 {
  1018.                     exiting = FALSE;
  1019.                     settmode(1);
  1020.                     break;
  1021.                 }
  1022.                 getout(0);
  1023.  
  1024.         case CMD_stop:
  1025.         case CMD_suspend:
  1026.                 if (!forceit && Changed)
  1027.                     autowrite();
  1028.                 gotocmdend();
  1029.                 flushbuf();
  1030.                 stoptermcap();
  1031.                 mch_suspend();        /* call machine specific function */
  1032.                 starttermcap();
  1033.                 must_redraw = CLEAR;
  1034.                 break;
  1035.  
  1036.         case CMD_xit:
  1037.         case CMD_wq:
  1038.                 if (!check_more(FALSE))        /* if more files we won't exit */
  1039.                     exiting = TRUE;
  1040.                 if (((cmdidx == CMD_wq || Changed) &&
  1041.                      (check_readonly() || !dowrite(arg, FALSE))) ||
  1042.                     check_more(TRUE))
  1043.                 {
  1044.                     exiting = FALSE;
  1045.                     settmode(1);
  1046.                     break;
  1047.                 }
  1048.                 getout(0);
  1049.  
  1050.         case CMD_args:
  1051.                 if (numfiles == 0)            /* no file name list */
  1052.                 {
  1053.                     if (!check_fname())        /* check for no file name at all */
  1054.                         smsg("[%s]", Filename);
  1055.                     break;
  1056.                 }
  1057.                 gotocmdline(TRUE, NUL);
  1058.                 for (i = 0; i < numfiles; ++i)
  1059.                 {
  1060.                     if (i == curfile)
  1061.                         outchar('[');
  1062.                     outstrn(files[i]);
  1063.                     if (i == curfile)
  1064.                         outchar(']');
  1065.                     outchar(' ');
  1066.                 }
  1067.                 outchar('\n');
  1068.                 wait_return(TRUE);
  1069.                 break;
  1070.  
  1071.         case CMD_wnext:
  1072.                 n = line2;
  1073.                 line1 = 1;
  1074.                 line2 = line_count;
  1075.                 dowrite(arg, FALSE);
  1076.                 line2 = n;
  1077.                 arg = (u_char *)"";        /* no file list */
  1078.                 /*FALLTHROUGH*/
  1079.  
  1080.         case CMD_next:
  1081.                 if (check_changed(TRUE))
  1082.                     break;
  1083.                 if (*arg != NUL)        /* redefine file list */
  1084.                 {
  1085.                     if (doarglist((char *)arg))
  1086.                         break;
  1087.                     i = 0;
  1088.                 }
  1089.                 else
  1090.                 {
  1091.                     if (addr_count == 0)
  1092.                         i = curfile + 1;
  1093.                     else
  1094.                         i = curfile + (int)line2;
  1095.                 }
  1096.  
  1097. donextfile:        if (i < 0 || i >= numfiles)
  1098.                 {
  1099.                     emsg(e_nomore);
  1100.                     break;
  1101.                 }
  1102.                 if (check_changed(TRUE))
  1103.                     break;
  1104.                 curfile = i;
  1105.                 doecmd(files[curfile], NULL);
  1106.                 break;
  1107.  
  1108.         case CMD_previous:
  1109.         case CMD_Next:
  1110.                 if (addr_count == 0)
  1111.                     i = curfile - 1;
  1112.                 else
  1113.                     i = curfile - (int)line2;
  1114.                 goto donextfile;
  1115.  
  1116.         case CMD_rewind:
  1117.                 i = 0;
  1118.                 goto donextfile;
  1119.  
  1120.         case CMD_write:
  1121.                 if (usefilter)        /* input lines to shell command */
  1122.                     dofilter(arg, TRUE, FALSE);
  1123.                 else
  1124.                     dowrite(arg, append);
  1125.                 break;
  1126.  
  1127.         case CMD_edit:
  1128.         case CMD_ex:
  1129.         case CMD_visual:
  1130.                 doecmd((char *)arg, NULL);
  1131.                 break;
  1132.  
  1133.         case CMD_file:
  1134.                 if (*arg != NUL)
  1135.                 {
  1136.                     setfname((char *)arg, NULL);
  1137.                     NotEdited = TRUE;
  1138.                     maketitle();
  1139.                 }
  1140.                 fileinfo(did_cd);        /* print full filename if :cd used */
  1141.                 break;
  1142.  
  1143.         case CMD_files:
  1144. #ifdef AMIGA
  1145.                 settmode(0);            /* set cooked mode, so output can be halted */
  1146. #endif
  1147.                 for (i = 0; i < NUMALTFILES; ++i)
  1148.                 {
  1149.                     if (altfiles[i])
  1150.                     {
  1151.                         sprintf(IObuff, "%2d \"%s\" line %ld\n", i, altfiles[i], (long)altlnum[i]);
  1152.                         outstrn(IObuff);
  1153.                     }
  1154.                     flushbuf();
  1155.                 }
  1156. #ifdef AMIGA
  1157.                 settmode(1);
  1158. #endif
  1159.                 wait_return(TRUE);
  1160.                 break;
  1161.  
  1162.         case CMD_read:
  1163.                 if (usefilter)
  1164.                 {
  1165.                     dofilter(arg, FALSE, TRUE);            /* :r!cmd */
  1166.                     break;
  1167.                 }
  1168.                 if (!u_save(line2, (linenr_t)(line2 + 1)))
  1169.                     break;
  1170.                 if (readfile((char *)arg, NULL, line2, FALSE))
  1171.                 {
  1172.                     emsg(e_notopen);
  1173.                     break;
  1174.                 }
  1175.                 updateScreen(NOT_VALID);
  1176.                 break;
  1177.  
  1178.         case CMD_cd:
  1179.         case CMD_chdir:
  1180. #ifdef UNIX
  1181.                 /*
  1182.                  * for UNIX ":cd" means: go to home directory
  1183.                  */
  1184.                 if (*arg == NUL)     /* use IObuff for home directory name */
  1185.                 {
  1186.                     expand_env("$HOME", IObuff, IOSIZE);
  1187.                     arg = (u_char *)IObuff;
  1188.                 }
  1189. #endif
  1190.                 if (*arg != NUL)
  1191.                 {
  1192.                     if (!did_cd)
  1193.                     {
  1194.                         scriptfullpath();
  1195.                         xFilename = Filename;
  1196.                     }
  1197.                     did_cd = TRUE;
  1198.                     if (chdir((char *)arg))
  1199.                         emsg(e_failed);
  1200.                     break;
  1201.                 }
  1202.                 /*FALLTHROUGH*/
  1203.  
  1204.         case CMD_pwd:
  1205.                 if (dirname(IObuff, IOSIZE))
  1206.                     msg(IObuff);
  1207.                 else
  1208.                     emsg(e_unknown);
  1209.                 break;
  1210.  
  1211.         case CMD_equal:
  1212.                 smsg("line %ld", (long)line2);
  1213.                 break;
  1214.  
  1215.         case CMD_list:
  1216.                 i = p_list;
  1217.                 p_list = 1;
  1218.         case CMD_number:
  1219.         case CMD_print:
  1220. #ifdef AMIGA
  1221.                 settmode(0);            /* set cooked mode, so output can be halted */
  1222. #endif
  1223.                 gotocmdline(TRUE, NUL);    /* clear command line */
  1224.                 n = 0;
  1225.                 for (;;)
  1226.                 {
  1227.                     if (p_nu || cmdidx == CMD_number)
  1228.                     {
  1229.                         sprintf(IObuff, "%7ld ", (long)line1);
  1230.                         outstrn(IObuff);
  1231.                         n += 8;
  1232.                     }
  1233.                     n += prt_line(nr2ptr(line1));
  1234.                     if (++line1 > line2)
  1235.                         break;
  1236.                     outchar('\n');
  1237.                     flushbuf();
  1238.                     n = Columns;        /* call wait_return later */
  1239.                 }
  1240. #ifdef AMIGA
  1241.                 settmode(1);
  1242. #endif
  1243.  
  1244.                 if (cmdidx == CMD_list)
  1245.                     p_list = i;
  1246.  
  1247.                     /*
  1248.                      * if we have one line that runs into the shown command,
  1249.                      * or more than one line, call wait_return()
  1250.                      */
  1251.                 if (n >= sc_col || global_busy)
  1252.                 {
  1253.                     outchar('\n');
  1254.                     wait_return(TRUE);
  1255.                 }
  1256.                 break;
  1257.  
  1258.         case CMD_shell:
  1259.                 doshell(NULL);
  1260.                 break;
  1261.  
  1262.         case CMD_tag:
  1263.                 dotag((char *)arg, 0, addr_count ? (int)line2 : 1);
  1264.                 break;
  1265.  
  1266.         case CMD_pop:
  1267.                 dotag("", 1, addr_count ? (int)line2 : 1);
  1268.                 break;
  1269.  
  1270.         case CMD_tags:
  1271.                 dotags();
  1272.                 break;
  1273.  
  1274.         case CMD_marks:
  1275.                 domarks();
  1276.                 break;
  1277.  
  1278.         case CMD_jumps:
  1279.                 dojumps();
  1280.                 break;
  1281.  
  1282.         case CMD_digraphs:
  1283. #ifdef DIGRAPHS
  1284.                 if (*arg)
  1285.                     putdigraph((char *)arg);
  1286.                 else
  1287.                     listdigraphs();
  1288. #else
  1289.                 emsg("No digraphs in this version");
  1290. #endif /* DIGRAPHS */
  1291.                 break;
  1292.  
  1293.         case CMD_set:
  1294.                 doset((char *)arg);
  1295.                 break;
  1296.  
  1297.         case CMD_abbreviate:
  1298.         case CMD_cabbrev:
  1299.         case CMD_iabbrev:
  1300.         case CMD_cnoreabbrev:
  1301.         case CMD_inoreabbrev:
  1302.         case CMD_noreabbrev:
  1303.         case CMD_unabbreviate:
  1304.         case CMD_cunabbrev:
  1305.         case CMD_iunabbrev:
  1306.                 i = ABBREV;
  1307.                 goto doabbr;        /* almost the same as mapping */
  1308.  
  1309.         case CMD_cmap:
  1310.         case CMD_imap:
  1311.         case CMD_map:
  1312.         case CMD_cnoremap:
  1313.         case CMD_inoremap:
  1314.         case CMD_noremap:
  1315.                 /*
  1316.                  * If we are sourcing .exrc or .vimrc in current directory we
  1317.                  * print the mappings for security reasons.
  1318.                  */
  1319.                 if (secure)
  1320.                 {
  1321.                     secure = 2;
  1322.                     outtrans((char *)cmd, -1);
  1323.                     outchar('\n');
  1324.                 }
  1325.         case CMD_cunmap:
  1326.         case CMD_iunmap:
  1327.         case CMD_unmap:
  1328.                 i = 0;
  1329. doabbr:
  1330.                 if (*cmd == 'c')        /* cmap, cunmap, cnoremap, etc. */
  1331.                 {
  1332.                     i += CMDLINE;
  1333.                     ++cmd;
  1334.                 }
  1335.                 else if (*cmd == 'i')    /* imap, iunmap, inoremap, etc. */
  1336.                 {
  1337.                     i += INSERT;
  1338.                     ++cmd;
  1339.                 }
  1340.                 else if (forceit || i)    /* map!, unmap!, noremap!, abbrev */
  1341.                     i += INSERT + CMDLINE;
  1342.                 else
  1343.                     i += NORMAL;            /* map, unmap, noremap */
  1344.                 switch (domap((*cmd == 'n') ? 2 : (*cmd == 'u'), (char *)arg, i))
  1345.                 {
  1346.                     case 1: emsg(e_invarg);
  1347.                             break;
  1348.                     case 2: emsg(e_nomap);
  1349.                             break;
  1350.                     case 3: emsg(e_ambmap);
  1351.                             break;
  1352.                 }
  1353.                 break;
  1354.  
  1355.         case CMD_display:
  1356.                 outchar('\n');
  1357.                 dodis();        /* display buffer contents */
  1358.                 break;
  1359.  
  1360.         case CMD_help:
  1361.                 help();
  1362.                 break;
  1363.  
  1364.         case CMD_version:
  1365.                 msg(longVersion);
  1366.                 break;
  1367.  
  1368.         case CMD_winsize:
  1369.                 line1 = getdigits((char **)&arg);
  1370.                 skipspace((char **)&arg);
  1371.                 line2 = getdigits((char **)&arg);
  1372.                 set_winsize((int)line1, (int)line2, TRUE);
  1373.                 break;
  1374.  
  1375.         case CMD_delete:
  1376.         case CMD_yank:
  1377.         case CMD_rshift:
  1378.         case CMD_lshift:
  1379.                 yankbuffer = regname;
  1380.                 startop.lnum = line1;
  1381.                 endop.lnum = line2;
  1382.                 nlines = line2 - line1 + 1;
  1383.                 mtype = MLINE;
  1384.                 Curpos.lnum = line1;
  1385.                 switch (cmdidx)
  1386.                 {
  1387.                 case CMD_delete:
  1388.                     dodelete();
  1389.                     break;
  1390.                 case CMD_yank:
  1391.                     doyank(FALSE);
  1392.                     break;
  1393.                 case CMD_rshift:
  1394.                     doshift(RSHIFT);
  1395.                     break;
  1396.                 case CMD_lshift:
  1397.                     doshift(LSHIFT);
  1398.                     break;
  1399.                 }
  1400.                 break;
  1401.  
  1402.         case CMD_put:
  1403.                 yankbuffer = regname;
  1404.                 Curpos.lnum = line2;
  1405.                 doput(forceit ? BACKWARD : FORWARD, -1L);
  1406.                 break;
  1407.  
  1408.         case CMD_t:
  1409.         case CMD_copy:
  1410.         case CMD_move:
  1411.                 n = get_address(&arg);
  1412.                 if (n == INVLNUM)
  1413.                 {
  1414.                     emsg(e_invaddr);
  1415.                     break;
  1416.                 }
  1417.  
  1418.                 if (cmdidx == CMD_move)
  1419.                 {
  1420.                     if (n >= line1 && n < line2 && line2 > line1)
  1421.                     {
  1422.                         emsg("Move lines into themselves");
  1423.                         break;
  1424.                     }
  1425.                     if (n >= line1)
  1426.                     {
  1427.                         --n;
  1428.                         Curpos.lnum = n - (line2 - line1) + 1;
  1429.                     }
  1430.                     else
  1431.                         Curpos.lnum = n + 1;
  1432.                     while (line1 <= line2)
  1433.                     {
  1434.                             /* this undo is not efficient, but it works */
  1435.                         u_save(line1 - 1, line1 + 1);
  1436.                         q = delsline(line1, FALSE);
  1437.                         u_save(n, n + 1);
  1438.                         appendline(n, q);
  1439.                         if (n < line1)
  1440.                         {
  1441.                             ++n;
  1442.                             ++line1;
  1443.                         }
  1444.                         else
  1445.                             --line2;
  1446.                     }
  1447.                 }
  1448.                 else
  1449.                 {
  1450.                     /*
  1451.                      * there are three situations:
  1452.                      * 1. destination is above line1
  1453.                      * 2. destination is between line1 and line2
  1454.                      * 3. destination is below line2
  1455.                      *
  1456.                      * n = destination (when starting)
  1457.                      * Curpos.lnum = destination (while copying)
  1458.                      * line1 = start of source (while copying)
  1459.                      * line2 = end of source (while copying)
  1460.                      */
  1461.                     u_save(n, n + 1);
  1462.                     Curpos.lnum = n;
  1463.                     lnum = line2 - line1 + 1;
  1464.                     while (line1 <= line2)
  1465.                     {
  1466.                         appendline(Curpos.lnum, save_line(nr2ptr(line1)));
  1467.                                 /* situation 2: skip already copied lines */
  1468.                         if (line1 == n)
  1469.                             line1 = Curpos.lnum;
  1470.                         ++line1;
  1471.                         if (Curpos.lnum < line1)
  1472.                             ++line1;
  1473.                         if (Curpos.lnum < line2)
  1474.                             ++line2;
  1475.                         ++Curpos.lnum;
  1476.                     }
  1477.                     msgmore((long)lnum);
  1478.                 }
  1479.                 u_clearline();
  1480.                 Curpos.col = 0;
  1481.                 updateScreen(NOT_VALID);
  1482.                 break;
  1483.  
  1484.         case CMD_and:
  1485.         case CMD_substitute:
  1486.                 dosub(line1, line2, (char *)arg, &nextcomm);
  1487.                 break;
  1488.  
  1489.         case CMD_join:
  1490.                 Curpos.lnum = line1;
  1491.                 if (line1 == line2)
  1492.                 {
  1493.                     if (line2 == line_count)
  1494.                     {
  1495.                         beep();
  1496.                         break;
  1497.                     }
  1498.                     ++line2;
  1499.                 }
  1500.                 dodojoin(line2 - line1 + 1, !forceit, TRUE);
  1501.                 break;
  1502.  
  1503.         case CMD_global:
  1504.                 if (forceit)
  1505.                     *cmd = 'v';
  1506.         case CMD_vglobal:
  1507.                 doglob(*cmd, line1, line2, (char *)arg);
  1508.                 break;
  1509.  
  1510.         case CMD_at:                /* :[addr]@r */
  1511.                 Curpos.lnum = line2;
  1512.                 if (!doexecbuf(*arg))        /* put the register in mapbuf */
  1513.                     beep();
  1514.                 else
  1515.                     docmdline(NULL);        /* execute from the mapbuf */
  1516.                 break;
  1517.  
  1518.         case CMD_bang:
  1519.                 dobang(addr_count, arg);
  1520.                 break;
  1521.  
  1522.         case CMD_undo:
  1523.                 u_undo(1);
  1524.                 break;
  1525.  
  1526.         case CMD_redo:
  1527.                 u_redo(1);
  1528.                 break;
  1529.  
  1530.         case CMD_source:
  1531.                 if (forceit)    /* :so! read vi commands */
  1532.                     openscript((char *)arg);
  1533.                 else if (dosource((char *)arg))        /* :so read ex commands */
  1534.                     emsg(e_notopen);
  1535.                 break;
  1536.  
  1537.         case CMD_mkvimrc:
  1538.                 if (*arg == NUL)
  1539.                     arg = (u_char *)VIMRC_FILE;
  1540.                 /*FALLTHROUGH*/
  1541.  
  1542.         case CMD_mkexrc:
  1543.                 {
  1544.                     FILE    *fd;
  1545.  
  1546.                     if (*arg == NUL)
  1547.                         arg = (u_char *)EXRC_FILE;
  1548. #ifdef UNIX
  1549.                         /* with Unix it is possible to open a directory */
  1550.                     if (isdir((char *)arg) > 0)
  1551.                     {
  1552.                         emsg2("\"%s\" is a directory", (char *)arg);
  1553.                         break;
  1554.                     }
  1555. #endif
  1556.                     if (!forceit && (fd = fopen((char *)arg, "r")) != NULL)
  1557.                     {
  1558.                         fclose(fd);
  1559.                         emsg2("\"%s\" exists (use ! to override)", (char *)arg);
  1560.                         break;
  1561.                     }
  1562.  
  1563.                     if ((fd = fopen((char *)arg, "w")) == NULL)
  1564.                     {
  1565.                         emsg2("Cannot open \"%s\" for writing", (char *)arg);
  1566.                         break;
  1567.                     }
  1568.                     if (makemap(fd) || makeset(fd) || fclose(fd))
  1569.                         emsg(e_write);
  1570.                     break;
  1571.                 }
  1572.  
  1573.         case CMD_cc:
  1574.                     qf_jump(atoi((char *)arg));
  1575.                     break;
  1576.  
  1577.         case CMD_cf:
  1578.                     if (*arg != NUL)
  1579.                     {
  1580.                         /*
  1581.                          * Great trick: Insert 'ef=' before arg.
  1582.                          * Always ok, because "cf " must be there.
  1583.                          */
  1584.                         arg -= 3;
  1585.                         arg[0] = 'e';
  1586.                         arg[1] = 'f';
  1587.                         arg[2] = '=';
  1588.                         doset((char *)arg);
  1589.                     }
  1590.                     qf_init();
  1591.                     break;
  1592.  
  1593.         case CMD_cl:
  1594.                     qf_list();
  1595.                     break;
  1596.  
  1597.         case CMD_cn:
  1598.                     qf_jump(-1);
  1599.                     break;
  1600.  
  1601.         case CMD_cp:
  1602.                     qf_jump(-2);
  1603.                     break;
  1604.  
  1605.         case CMD_cq:
  1606.                     getout(1);        /* this does not always work. why? */
  1607.  
  1608.         case CMD_mark:
  1609.         case CMD_k:
  1610.                     pos = Curpos;            /* save Curpos */
  1611.                     Curpos.lnum = line2;
  1612.                     Curpos.col = 0;
  1613.                     setmark(*arg);            /* set mark */
  1614.                     Curpos = pos;            /* restore Curpos */
  1615.                     break;
  1616.  
  1617. #ifdef SETKEYMAP
  1618.         case CMD_setkeymap:
  1619.                     set_keymap(arg);
  1620.                     break;
  1621. #endif
  1622.  
  1623.         case CMD_center:
  1624.         case CMD_right:
  1625.         case CMD_left:
  1626.                     do_align(line1, line2, atoi((char *)arg),
  1627.                             cmdidx == CMD_center ? 0 : cmdidx == CMD_right ? 1 : -1);
  1628.                     break;
  1629.  
  1630.         case CMD_make:
  1631.                     domake((char *)arg);
  1632.                     break;
  1633.  
  1634.         default:
  1635.                     emsg(e_invcmd);
  1636.     }
  1637.  
  1638.  
  1639. doend:
  1640.     forceit = FALSE;        /* reset now so it can be used in getfile() */
  1641.     return nextcomm;
  1642. }
  1643.  
  1644. /*
  1645.  * handle the :! command.
  1646.  * We replace the extra bangs by the previously entered command and remember
  1647.  * the command.
  1648.  */
  1649.     static void
  1650. dobang(addr_count, arg)
  1651.     int        addr_count;
  1652.     u_char    *arg;
  1653. {
  1654.     static    char    *prevcmd = NULL;        /* the previous command */
  1655.     char            *t;
  1656.     char            *trailarg;
  1657.     int             len;
  1658.  
  1659.     /*
  1660.      * Disallow shell commands from .exrc and .vimrc in current directory for
  1661.      * security reasons.
  1662.      */
  1663.     if (secure)
  1664.     {
  1665.         secure = 2;
  1666.         emsg(e_curdir);
  1667.         return;
  1668.     }
  1669.     len = strlen((char *)arg) + 1;
  1670.  
  1671.     if (Changed)
  1672.         autowrite();
  1673.     /*
  1674.      * try to find an embedded bang, like in :!<cmd> ! [args]
  1675.      * (:!! is indicated by the 'forceit' variable)
  1676.      */
  1677.     trailarg = (char *)arg;
  1678.     skiptospace(&trailarg);
  1679.     skipspace(&trailarg);
  1680.     if (*trailarg == '!')
  1681.         *trailarg++ = NUL;
  1682.     else
  1683.         trailarg = NULL;
  1684.  
  1685.     if (forceit || trailarg != NULL)            /* use the previous command */
  1686.     {
  1687.         if (prevcmd == NULL)
  1688.         {
  1689.             emsg(e_noprev);
  1690.             return;
  1691.         }
  1692.         len += strlen(prevcmd) * (trailarg != NULL && forceit ? 2 : 1);
  1693.     }
  1694.  
  1695.     if (len > CMDBUFFSIZE)
  1696.     {
  1697.         emsg(e_toolong);
  1698.         return;
  1699.     }
  1700.     if ((t = alloc(len)) == NULL)
  1701.         return;
  1702.     *t = NUL;
  1703.     if (forceit)
  1704.         strcpy(t, prevcmd);
  1705.     strcat(t, (char *)arg);
  1706.     if (trailarg != NULL)
  1707.     {
  1708.         strcat(t, prevcmd);
  1709.         strcat(t, trailarg);
  1710.     }
  1711.     free(prevcmd);
  1712.     prevcmd = t;
  1713.  
  1714.     if (bangredo)            /* put cmd in redo buffer for ! command */
  1715.     {
  1716.         AppendToRedobuff(prevcmd);
  1717.         AppendToRedobuff("\n");
  1718.         bangredo = FALSE;
  1719.     }
  1720.         /* echo the command */
  1721.     gotocmdline(TRUE, ':');
  1722.     if (addr_count)                        /* :range! */
  1723.     {
  1724.         outnum((long)line1);
  1725.         outchar(',');
  1726.         outnum((long)line2);
  1727.     }
  1728.     outchar('!');
  1729.     outtrans(prevcmd, -1);
  1730.  
  1731.     if (addr_count == 0)                /* :! */
  1732.         doshell(prevcmd); 
  1733.     else                                /* :range! */
  1734.         dofilter((u_char *)prevcmd, TRUE, TRUE);
  1735. }
  1736.  
  1737.     static int
  1738. autowrite()
  1739. {
  1740.     if (!p_aw || check_readonly() || check_fname())
  1741.         return FALSE;
  1742.     return (writeit(Filename, sFilename, (linenr_t)1, line_count, 0, 0, TRUE));
  1743. }
  1744.  
  1745.     static int
  1746. dowrite(arg, append)
  1747.     u_char    *arg;
  1748.     int        append;
  1749. {
  1750.     FILE    *f;
  1751.     int        other;
  1752.  
  1753.     /*
  1754.      * if we have a new file name put it in the list of alternate file names
  1755.      */
  1756.     other = otherfile((char *)arg);
  1757.     if (*arg != NUL && other)
  1758.         setaltfname(strsave((char *)arg), strsave((char *)arg), (linenr_t)1, TRUE);
  1759.  
  1760.     /*
  1761.      * writing to the current file is not allowed in readonly mode
  1762.      */
  1763.     if ((*arg == NUL || !other) && check_readonly())
  1764.         return FALSE;
  1765.  
  1766.     /*
  1767.      * write to current file
  1768.      */
  1769.     if (*arg == NUL || !other)
  1770.     {
  1771.         if (check_fname())
  1772.             return FALSE;
  1773.         return (writeit(Filename, sFilename, line1, line2, append, forceit, TRUE));
  1774.     }
  1775.  
  1776.     /*
  1777.      * write to other file; overwriting only allowed with '!'
  1778.      */
  1779.     if (!forceit && !append && !p_wa && (f = fopen((char *)arg, "r")) != NULL)
  1780.     {                                /* don't overwrite existing file */
  1781.             fclose(f);
  1782. #ifdef UNIX
  1783.                 /* with UNIX it is possible to open a directory */
  1784.             if (isdir((char *)arg) > 0)
  1785.                 emsg2("\"%s\" is a directory", (char *)arg);
  1786.             else
  1787. #endif
  1788.                 emsg(e_exists);
  1789.             return 0;
  1790.     }
  1791.     return (writeit((char *)arg, NULL, line1, line2, append, forceit, TRUE));
  1792. }
  1793.  
  1794.     static int
  1795. doecmd(arg, sarg)
  1796.     char        *arg;
  1797.     char        *sarg;
  1798. {
  1799.     int            setalt;
  1800.     char        *command = NULL;
  1801.     int            redraw_save;
  1802.     linenr_t    newlnum;
  1803.  
  1804.     newlnum = doecmdlnum;
  1805.     doecmdlnum = 0;                        /* reset it for next time */
  1806.  
  1807.     if (*arg == '+')        /* :e +[command] file */
  1808.     {
  1809.         ++arg;
  1810.         if (isspace(*arg))
  1811.             command = "$";
  1812.         else
  1813.         {
  1814.             command = arg;
  1815.             while (*arg && !isspace(*arg))
  1816.                 ++arg;
  1817.         }
  1818.         if (*arg)
  1819.             *arg++ = NUL;
  1820.         
  1821.         skipspace(&arg);
  1822.     }
  1823.  
  1824.     if (sarg == NULL)
  1825.         sarg = arg;
  1826.  
  1827. #ifdef AMIGA
  1828.     fname_case(arg);                /* set correct case for filename */
  1829. #endif
  1830.  
  1831.     setalt = (*arg != NUL && otherfile(arg));
  1832.     if (check_changed(FALSE))
  1833.     {
  1834.         if (setalt)
  1835.             setaltfname(strsave(arg), strsave(sarg), (linenr_t)1, TRUE);
  1836.         return FALSE;
  1837.     }
  1838.     if (setalt)
  1839.     {
  1840.         setaltfname(Filename, sFilename, Curpos.lnum, FALSE);
  1841.         Filename = NULL;
  1842.         sFilename = NULL;
  1843.         setfname(arg, sarg);
  1844.     }
  1845.     else if (newlnum == 0)
  1846.         newlnum = Curpos.lnum;
  1847.     maketitle();
  1848.     if (check_fname())
  1849.         return FALSE;
  1850.  
  1851.     /* clear mem and read file */
  1852.     freeall();
  1853.     filealloc();
  1854.     startop.lnum = 0;    /* clear '[ and '] marks */
  1855.     endop.lnum = 0;
  1856.  
  1857.     redraw_save = RedrawingDisabled;
  1858.     RedrawingDisabled = TRUE;        /* don't redraw until the cursor is in
  1859.                                      * the right line */
  1860.     startscript();                    /* re-start auto script file */
  1861.     readfile(Filename, sFilename, (linenr_t)0, TRUE);
  1862.     if (newlnum && command == NULL)
  1863.     {
  1864.         if (newlnum != INVLNUM)
  1865.             Curpos.lnum = newlnum;
  1866.         else
  1867.             Curpos.lnum = line_count;
  1868.         Curpos.col = 0;
  1869.     }
  1870.     UNCHANGED;
  1871.     if (command)
  1872.         docmdline((u_char *)command);
  1873.     RedrawingDisabled = redraw_save;    /* cursupdate() will redraw the screen later */
  1874.     if (p_im)
  1875.         stuffReadbuff("i");            /* start editing in insert mode */
  1876.     return TRUE;
  1877. }
  1878.  
  1879.     static void
  1880. doshell(cmd)
  1881.     char    *cmd;
  1882. {
  1883.     /*
  1884.      * Disallow shell commands from .exrc and .vimrc in current directory for
  1885.      * security reasons.
  1886.      */
  1887.     if (secure)
  1888.     {
  1889.         secure = 2;
  1890.         emsg(e_curdir);
  1891.         return;
  1892.     }
  1893.     stoptermcap();
  1894.     outchar('\n');                    /* shift screen one line up */
  1895.  
  1896.         /* warning message before calling the shell */
  1897.     if (p_warn && Changed)
  1898.     {
  1899.         gotocmdline(TRUE, NUL);
  1900.         outstr("[No write since last change]\n");
  1901.     }
  1902.     call_shell(cmd, 0, TRUE);
  1903.  
  1904. #ifdef AMIGA
  1905.     wait_return(!term_console);        /* see below */
  1906. #else
  1907.     wait_return(TRUE);                /* includes starttermcap() */
  1908. #endif
  1909.  
  1910.     /*
  1911.      * In an Amiga window redrawing is caused by asking the window size.
  1912.      * If we got an interrupt this will not work. The chance that the window
  1913.      * size is wrong is very small, but we need to redraw the screen.
  1914.      */
  1915. #ifdef AMIGA
  1916.     if (term_console)
  1917.     {
  1918.         outstr("\033[0 q");     /* get window size */
  1919.         if (got_int)
  1920.             must_redraw = CLEAR;    /* if got_int is TRUE we have to redraw */
  1921.         else
  1922.             must_redraw = FALSE;    /* no extra redraw needed */
  1923.     }
  1924. #endif /* AMIGA */
  1925. }
  1926.  
  1927. /*
  1928.  * dofilter: filter lines through a command given by the user
  1929.  *
  1930.  * We use temp files and the call_shell() routine here. This would normally
  1931.  * be done using pipes on a UNIX machine, but this is more portable to
  1932.  * the machines we usually run on. The call_shell() routine needs to be able
  1933.  * to deal with redirection somehow, and should handle things like looking
  1934.  * at the PATH env. variable, and adding reasonable extensions to the
  1935.  * command name given by the user. All reasonable versions of call_shell()
  1936.  * do this.
  1937.  * We use input redirection if do_in is TRUE.
  1938.  * We use output redirection if do_out is TRUE.
  1939.  */
  1940.     static void
  1941. dofilter(buff, do_in, do_out)
  1942.     u_char        *buff;
  1943.     int            do_in, do_out;
  1944. {
  1945. #ifdef LATTICE
  1946.     char        itmp[L_tmpnam];        /* use tmpnam() */
  1947.     char        otmp[L_tmpnam];
  1948. #else
  1949.     char        itmp[TMPNAMELEN];
  1950.     char        otmp[TMPNAMELEN];
  1951. #endif
  1952.     linenr_t     linecount;
  1953.  
  1954.     /*
  1955.      * Disallow shell commands from .exrc and .vimrc in current directory for
  1956.      * security reasons.
  1957.      */
  1958.     if (secure)
  1959.     {
  1960.         secure = 2;
  1961.         emsg(e_curdir);
  1962.         return;
  1963.     }
  1964.     if (*buff == NUL)        /* no filter command */
  1965.         return;
  1966.     linecount = line2 - line1 + 1;
  1967.     Curpos.lnum = line1;
  1968.     Curpos.col = 0;
  1969.     /* cursupdate(); */
  1970.  
  1971.     /*
  1972.      * 1. Form temp file names
  1973.      * 2. Write the lines to a temp file
  1974.      * 3. Run the filter command on the temp file
  1975.      * 4. Read the output of the command into the buffer
  1976.      * 5. Delete the original lines to be filtered
  1977.      * 6. Remove the temp files
  1978.      */
  1979.  
  1980. #ifndef LATTICE
  1981.     /* for lattice we use tmpnam(), which will make its own name */
  1982.     strcpy(itmp, TMPNAME1);
  1983.     strcpy(otmp, TMPNAME2);
  1984. #endif
  1985.  
  1986.     if ((do_in && *mktemp(itmp) == NUL) || (do_out && *mktemp(otmp) == NUL))
  1987.     {
  1988.         emsg(e_notmp);
  1989.         return;
  1990.     }
  1991.  
  1992. /*
  1993.  * ! command will be overwritten by next mesages
  1994.  * This is a trade off between showing the command and not scrolling the
  1995.  * text one line up (problem on slow terminals).
  1996.  */
  1997.     must_redraw = CLEAR;        /* screen has been shifted up one line */
  1998.     if (do_in && !writeit(itmp, NULL, line1, line2, FALSE, 0, FALSE))
  1999.     {
  2000.         outchar('\n');            /* keep message from writeit() */
  2001.         emsg(e_notcreate);
  2002.         return;
  2003.     }
  2004.     if (!do_out)
  2005.         outchar('\n');
  2006.  
  2007. #ifdef UNIX
  2008. /*
  2009.  * put braces around the command (for concatenated commands)
  2010.  */
  2011.      sprintf(IObuff, "(%s)", (char *)buff);
  2012.     if (do_in)
  2013.     {
  2014.         strcat(IObuff, " < ");
  2015.         strcat(IObuff, itmp);
  2016.     }
  2017.     if (do_out)
  2018.     {
  2019.         strcat(IObuff, " > ");
  2020.         strcat(IObuff, otmp);
  2021.     }
  2022. #else
  2023. /*
  2024.  * for shells that don't understand braces around commands, at least allow
  2025.  * the use of commands in a pipe.
  2026.  */
  2027.     strcpy(IObuff, (char *)buff);
  2028.     if (do_in)
  2029.     {
  2030.         char        *p;
  2031.     /*
  2032.      * If there is a pipe, we have to put the '<' in front of it
  2033.      */
  2034.         p = strchr(IObuff, '|');
  2035.         if (p)
  2036.             *p = NUL;
  2037.         strcat(IObuff, " < ");
  2038.         strcat(IObuff, itmp);
  2039.         p = strchr((char *)buff, '|');
  2040.         if (p)
  2041.             strcat(IObuff, p);
  2042.     }
  2043.     if (do_out)
  2044.     {
  2045.         strcat(IObuff, " > ");
  2046.         strcat(IObuff, otmp);
  2047.     }
  2048. #endif
  2049.  
  2050.     call_shell(IObuff, 1, FALSE);    /* errors are ignored, so you can see the error
  2051.                                    messages from the command; use 'u' to fix the
  2052.                                    text */
  2053.  
  2054.     if (do_out)
  2055.     {
  2056.         if (!u_save((linenr_t)(line2), (linenr_t)(line2 + 1)))
  2057.         {
  2058.             linecount = 0;
  2059.             goto error;
  2060.         }
  2061.         if (readfile(otmp, NULL, line2, FALSE))
  2062.         {
  2063.             outchar ('\n');
  2064.             emsg(e_notread);
  2065.             linecount = 0;
  2066.             goto error;
  2067.         }
  2068.  
  2069.         if (do_in)
  2070.         {
  2071.             Curpos.lnum = line1;
  2072.             dellines(linecount, TRUE, TRUE);
  2073.         }
  2074.     }
  2075.     else
  2076.     {
  2077. error:
  2078.         wait_return(FALSE);
  2079.     }
  2080.     updateScreen(CLEAR);        /* do this before messages below */
  2081.  
  2082.     if (linecount > p_report)
  2083.     {
  2084.         if (!do_in && do_out)
  2085.             msgmore(linecount);
  2086.         else
  2087.             smsg("%ld lines filtered", (long)linecount);
  2088.     }
  2089.     remove(itmp);
  2090.     remove(otmp);
  2091.     return;
  2092. }
  2093.  
  2094.     static void
  2095. domake(arg)
  2096.     char *arg;
  2097. {
  2098.     if (*p_ef == NUL)
  2099.     {
  2100.         emsg("errorfile option not set");
  2101.         return;
  2102.     }
  2103.     if (Changed)
  2104.         autowrite();
  2105.     remove(p_ef);
  2106.     outchar(':');
  2107.     outstr(arg);        /* show what we are doing */
  2108. #ifdef UNIX
  2109.     sprintf(IObuff, "%s |& tee %s", arg, p_ef);
  2110. #else
  2111.     sprintf(IObuff, "%s > %s", arg, p_ef);
  2112. #endif
  2113.     doshell(IObuff);
  2114. #ifdef AMIGA
  2115.     flushbuf();
  2116.     vpeekc();        /* read window status report and redraw before message */
  2117. #endif
  2118.     qf_init();
  2119.     remove(p_ef);
  2120. }
  2121.  
  2122. /* 
  2123.  * Redefine the argument list to 'str'.
  2124.  * Return TRUE for failure.
  2125.  */
  2126.     static int
  2127. doarglist(str)
  2128.     char *str;
  2129. {
  2130.     int        new_numfiles = 0;
  2131.     char    **new_files = NULL;
  2132.     int        exp_numfiles;
  2133.     char    **exp_files;
  2134.     char    **t;
  2135.     char    *p;
  2136.     int        inquote;
  2137.     int        i;
  2138.  
  2139.     while (*str)
  2140.     {
  2141.         /*
  2142.          * create a new entry in new_files[]
  2143.          */
  2144.         t = (char **)lalloc((u_long)(sizeof(char *) * (new_numfiles + 1)), TRUE);
  2145.         if (t != NULL)
  2146.             for (i = new_numfiles; --i >= 0; )
  2147.                 t[i] = new_files[i];
  2148.         free(new_files);
  2149.         if (t == NULL)
  2150.             return TRUE;
  2151.         new_files = t;
  2152.         new_files[new_numfiles++] = str;
  2153.  
  2154.         /*
  2155.          * isolate one argument, taking quotes
  2156.          */
  2157.         inquote = FALSE;
  2158.         for (p = str; *str; ++str)
  2159.         {
  2160.             if (*str == '\\' && *(str + 1) != NUL)
  2161.                 *p++ = *++str;
  2162.             else
  2163.             {
  2164.                 if (!inquote && isspace(*str))
  2165.                     break;
  2166.                 if (*str == '"')
  2167.                     inquote ^= TRUE;
  2168.                 else
  2169.                     *p++ = *str;
  2170.             }
  2171.         }
  2172.         skipspace(&str);
  2173.         *p = NUL;
  2174.     }
  2175.     
  2176.     if (ExpandWildCards(new_numfiles, new_files, &exp_numfiles, &exp_files, FALSE, TRUE) != 0)
  2177.         return TRUE;
  2178.     else if (exp_numfiles == 0)
  2179.     {
  2180.         emsg(e_nomatch);
  2181.         return TRUE;
  2182.     }
  2183.     if (files_exp)            /* files[] has been allocated, free it */
  2184.         FreeWild(numfiles, files);
  2185.     else
  2186.         files_exp = TRUE;
  2187.     files = exp_files;
  2188.     numfiles = exp_numfiles;
  2189.  
  2190.     return FALSE;
  2191. }
  2192.  
  2193.     void
  2194. gotocmdline(clr, firstc)
  2195.     int                clr;
  2196.     int                firstc;
  2197. {
  2198.     int        i;
  2199.  
  2200.     if (clr)            /* clear the bottom line(s) */
  2201.     {
  2202.         for (i = 0; i <= cmdoffset; ++i)
  2203.         {
  2204.             windgoto((int)Rows - i - 1, 0);
  2205.             clear_line();
  2206.         }
  2207.         redraw_msg = TRUE;
  2208.     }
  2209.     windgoto((int)Rows - cmdoffset - 1, 0);
  2210.     if (firstc)
  2211.         outchar(firstc);
  2212. }
  2213.  
  2214.     void
  2215. gotocmdend()
  2216. {
  2217.     windgoto((int)Rows - 1, 0);
  2218.     outchar('\n');
  2219. }
  2220.  
  2221.     static int
  2222. check_readonly()
  2223. {
  2224.     if (!forceit && p_ro)
  2225.     {
  2226.         emsg(e_readonly);
  2227.         return TRUE;
  2228.     }
  2229.     return FALSE;
  2230. }
  2231.  
  2232.     static int
  2233. check_changed(checkaw)
  2234.     int        checkaw;
  2235. {
  2236.     if (!forceit && Changed && (!checkaw || !autowrite()))
  2237.     {
  2238.         emsg(e_nowrtmsg);
  2239.         return TRUE;
  2240.     }
  2241.     return FALSE;
  2242. }
  2243.  
  2244.     int
  2245. check_fname()
  2246. {
  2247.     if (Filename == NULL)
  2248.     {
  2249.         emsg(e_noname);
  2250.         return TRUE;
  2251.     }
  2252.     return FALSE;
  2253. }
  2254.  
  2255.     static int
  2256. check_more(message)
  2257.     int message;            /* when FALSE check only, no messages */
  2258. {
  2259.     if (!forceit && curfile + 1 < numfiles && quitmore == 0)
  2260.     {
  2261.         if (message)
  2262.         {
  2263.             emsg(e_more);
  2264.             quitmore = 2;            /* next try to quit is allowed */
  2265.         }
  2266.         return TRUE;
  2267.     }
  2268.     return FALSE;
  2269. }
  2270.  
  2271. /*
  2272.  * try to abandon current file and edit "fname"
  2273.  * return 1 for "normal" error, 2 for "not written" error, 0 for success
  2274.  * -1 for succesfully opening another file
  2275.  */
  2276.     int
  2277. getfile(fname, sfname, setpm)
  2278.     char    *fname;
  2279.     char    *sfname;
  2280.     int        setpm;
  2281. {
  2282.     int other;
  2283.  
  2284.     other = otherfile(fname);
  2285.     if (other && !forceit && Changed && !autowrite())
  2286.     {
  2287.         emsg(e_nowrtmsg);
  2288.         return 2;        /* file has been changed */
  2289.     }
  2290.     if (setpm)
  2291.         setpcmark();
  2292.     if (!other)
  2293.         return 0;        /* it's in the same file */
  2294.     if (doecmd(fname, sfname))
  2295.         return -1;        /* opened another file */
  2296.     return 1;            /* error encountered */
  2297. }
  2298.  
  2299. /*
  2300.  * return TRUE if alternate file n is the same as the current file
  2301.  */
  2302.     int
  2303. samealtfile(n)
  2304.     int            n;
  2305. {
  2306.     if (n < NUMALTFILES && altfiles[n] != NULL && Filename != NULL &&
  2307.                     fnamecmp(altfiles[n], Filename) == 0)
  2308.         return TRUE;
  2309.     return FALSE;
  2310. }
  2311.  
  2312. /*
  2313.  * get alternate file n
  2314.  * set linenr to lnum or altlnum if lnum == 0
  2315.  * if (setpm) setpcmark
  2316.  * return 1 for failure, 0 for success
  2317.  */
  2318.     int
  2319. getaltfile(n, lnum, setpm)
  2320.     int            n;
  2321.     linenr_t    lnum;
  2322.     int            setpm;
  2323. {
  2324.     if (n < 0 || n >= NUMALTFILES || altfiles[n] == NULL)
  2325.     {
  2326.         emsg(e_noalt);
  2327.         return 1;
  2328.     }
  2329.     if (lnum == 0)
  2330.         lnum = altlnum[n];        /* altlnum may be changed by getfile() */
  2331.     RedrawingDisabled = TRUE;
  2332.     if (getfile(altfiles[n], saltfiles[n], setpm) <= 0)
  2333.     {
  2334.         RedrawingDisabled = FALSE;
  2335.         if (lnum == 0 || lnum > line_count)        /* check for valid lnum */
  2336.             Curpos.lnum = 1;
  2337.         else
  2338.             Curpos.lnum = lnum;
  2339.  
  2340.         Curpos.col = 0;
  2341.         return 0;
  2342.     }
  2343.     RedrawingDisabled = FALSE;
  2344.     return 1;
  2345. }
  2346.  
  2347. /*
  2348.  * get name of "n"th alternate file
  2349.  */
  2350.      char *
  2351. getaltfname(n)
  2352.     int n;
  2353. {
  2354.     if (n >= NUMALTFILES)
  2355.         return NULL;
  2356.     return altfiles[n];
  2357. }
  2358.  
  2359. /*
  2360.  * put name "arg" in the list of alternate files.
  2361.  * "arg" must have been allocated
  2362.  * "lnum" is the default line number when jumping to the file
  2363.  * "newfile" must be TRUE when "arg" != current file
  2364.  */
  2365.     static void
  2366. setaltfname(arg, sarg, lnum, newfile)
  2367.     char        *arg;
  2368.     char        *sarg;
  2369.     linenr_t    lnum;
  2370.     int            newfile;
  2371. {
  2372.     int i;
  2373.  
  2374.     free(altfiles[NUMALTFILES - 1]);
  2375.     free(saltfiles[NUMALTFILES - 1]);
  2376.     for (i = NUMALTFILES - 1; i > 0; --i)
  2377.     {
  2378.         altfiles[i] = altfiles[i - 1];
  2379.         saltfiles[i] = saltfiles[i - 1];
  2380.         altlnum[i] = altlnum[i - 1];
  2381.     }
  2382.     incrmarks();        /* increment file number for all jumpmarks */
  2383.     incrtags();            /* increment file number for all tags */
  2384.     if (newfile)
  2385.     {
  2386.         decrmarks();        /* decrement file number for jumpmarks in current file */
  2387.         decrtags();            /* decrement file number for tags in current file */
  2388.     }
  2389.  
  2390.     altfiles[0] = arg;
  2391.     saltfiles[0] = sarg;
  2392.     altlnum[0] = lnum;
  2393. }
  2394.  
  2395.     static void
  2396. nextwild(buff, type)
  2397.     u_char *buff;
  2398.     int        type;
  2399. {
  2400.     int        i;
  2401.     char    *p1, *p2;
  2402.     int        oldlen;
  2403.     int        difflen;
  2404.  
  2405.     outstr("...");        /* show that we are busy */
  2406.     flushbuf();
  2407.     i = cmdslen;
  2408.     cmdslen = cmdpos + 4;
  2409.     cmdchecklen();        /* check if we caused a scrollup */
  2410.     cmdslen = i;
  2411.  
  2412.     for (i = cmdpos; i > 0 && buff[i - 1] != ' '; --i)
  2413.         ;
  2414.     oldlen = cmdpos - i;
  2415.  
  2416.         /* add a "*" to the file name and expand it */
  2417.     if ((p1 = addstar((char *)&buff[i], oldlen)) != NULL)
  2418.     {
  2419.         if ((p2 = ExpandOne((u_char *)p1, FALSE, type)) != NULL)
  2420.         {
  2421.             if (cmdlen + (difflen = strlen(p2) - oldlen) > CMDBUFFSIZE - 4)
  2422.                 emsg(e_toolong);
  2423.             else
  2424.             {
  2425.                 strncpy((char *)&buff[cmdpos + difflen], (char *)&buff[cmdpos], (size_t)(cmdlen - cmdpos));
  2426.                 strncpy((char *)&buff[i], p2, strlen(p2));
  2427.                 cmdlen += difflen;
  2428.                 cmdpos += difflen;
  2429.             }
  2430.             free(p2);
  2431.         }
  2432.         free(p1);
  2433.     }
  2434.     redrawcmd();
  2435. }
  2436.  
  2437. /*
  2438.  * Do wildcard expansion on the string 'str'.
  2439.  * Return a pointer to alloced memory containing the new string.
  2440.  * Return NULL for failure.
  2441.  *
  2442.  * mode = -2: only release file names
  2443.  * mode = -1: normal expansion, do not keep file names
  2444.  * mode =  0: normal expansion, keep file names
  2445.  * mode =  1: use next match in multiple match
  2446.  * mode =  2: use previous match in multiple match
  2447.  * mode =  3: use next match in multiple match and wrap to first
  2448.  * mode =  4: return all matches concatenated
  2449.  * mode =  5: return longest matched part
  2450.  */
  2451.     char *
  2452. ExpandOne(str, list_notfound, mode)
  2453.     u_char    *str;
  2454.     int        list_notfound;
  2455.     int        mode;
  2456. {
  2457.     char        *ss = NULL;
  2458.     static char **cmd_files = NULL;      /* list of input files */
  2459.     static int    findex;
  2460.     int            i, found = 0;
  2461.     int            multmatch = FALSE;
  2462.     u_long        len;
  2463.     char        *filesuf, *setsuf, *nextsetsuf;
  2464.     int            filesuflen, setsuflen;
  2465.  
  2466. /*
  2467.  * first handle the case of using an old match
  2468.  */
  2469.     if (mode >= 1 && mode < 4)
  2470.     {
  2471.         if (cmd_numfiles > 0)
  2472.         {
  2473.             if (mode == 2)
  2474.                 --findex;
  2475.             else    /* mode == 1 || mode == 3 */
  2476.                 ++findex;
  2477.             if (findex < 0)
  2478.                 findex = 0;
  2479.             if (findex > cmd_numfiles - 1)
  2480.             {
  2481.                 if (mode == 3)
  2482.                     findex = 0;
  2483.                 else
  2484.                     findex = cmd_numfiles - 1;
  2485.             }
  2486.             return strsave(cmd_files[findex]);
  2487.         }
  2488.         else
  2489.             return NULL;
  2490.     }
  2491.  
  2492. /* free old names */
  2493.     if (cmd_numfiles != -1 && mode < 4)
  2494.     {
  2495.         FreeWild(cmd_numfiles, cmd_files);
  2496.         cmd_numfiles = -1;
  2497.     }
  2498.     findex = 0;
  2499.  
  2500.     if (mode == -2)        /* only release file name */
  2501.         return NULL;
  2502.  
  2503.     if (cmd_numfiles == -1)
  2504.     {
  2505.         if (ExpandWildCards(1, (char **)&str, &cmd_numfiles, &cmd_files, FALSE, list_notfound) != 0)
  2506.             /* error: do nothing */;
  2507.         else if (cmd_numfiles == 0)
  2508.             emsg(e_nomatch);
  2509.         else if (mode < 4)
  2510.         {
  2511.             if (cmd_numfiles > 1)        /* more than one match; check suffixes */
  2512.             {
  2513.                 found = -2;
  2514.                 for (i = 0; i < cmd_numfiles; ++i)
  2515.                 {
  2516.                     if ((filesuf = strrchr(cmd_files[i], '.')) != NULL)
  2517.                     {
  2518.                         filesuflen = strlen(filesuf);
  2519.                         for (setsuf = p_su; *setsuf; setsuf = nextsetsuf)
  2520.                         {
  2521.                             if ((nextsetsuf = strchr(setsuf + 1, '.')) == NULL)
  2522.                                 nextsetsuf = setsuf + strlen(setsuf);
  2523.                             setsuflen = (int)(nextsetsuf - setsuf);
  2524.                             if (filesuflen == setsuflen &&
  2525.                                         strncmp(setsuf, filesuf, (size_t)setsuflen) == 0)
  2526.                                 break;
  2527.                         }
  2528.                         if (*setsuf)                /* suffix matched: ignore file */
  2529.                             continue;
  2530.                     }
  2531.                     if (found >= 0)
  2532.                     {
  2533.                         multmatch = TRUE;
  2534.                         break;
  2535.                     }
  2536.                     found = i;
  2537.                 }
  2538.             }
  2539.             if (multmatch || found < 0)
  2540.             {
  2541.                 emsg(e_toomany);
  2542.                 found = 0;                /* return first one */
  2543.                 multmatch = TRUE;        /* for found < 0 */
  2544.             }
  2545.             if (found >= 0 && !(multmatch && mode == -1))
  2546.                 ss = strsave(cmd_files[found]);
  2547.         }
  2548.     }
  2549.  
  2550.     if (mode == 5 && cmd_numfiles > 0)        /* find longest common part */
  2551.     {
  2552.         for (len = 0; cmd_files[0][len]; ++len)
  2553.         {
  2554.             for (i = 0; i < cmd_numfiles; ++i)
  2555.             {
  2556. #ifdef AMIGA
  2557.                 if (toupper(cmd_files[i][len]) != toupper(cmd_files[0][len]))
  2558. #else
  2559.                 if (cmd_files[i][len] != cmd_files[0][len])
  2560. #endif
  2561.                     break;
  2562.             }
  2563.             if (i < cmd_numfiles)
  2564.                 break;
  2565.         }
  2566.         ss = alloc((unsigned)len + 1);
  2567.         if (ss)
  2568.         {
  2569.             strncpy(ss, cmd_files[0], (size_t)len);
  2570.             ss[len] = NUL;
  2571.         }
  2572.         multmatch = TRUE;                    /* don't free the names */
  2573.         findex = -1;                        /* next p_wc gets first one */
  2574.     }
  2575.  
  2576.     if (mode == 4 && cmd_numfiles > 0)        /* concatenate all file names */
  2577.     {
  2578.         len = 0;
  2579.         for (i = 0; i < cmd_numfiles; ++i)
  2580.             len += strlen(cmd_files[i]) + 1;
  2581.         ss = lalloc(len, TRUE);
  2582.         if (ss)
  2583.         {
  2584.             *ss = NUL;
  2585.             for (i = 0; i < cmd_numfiles; ++i)
  2586.             {
  2587.                 strcat(ss, cmd_files[i]);
  2588.                 if (i != cmd_numfiles - 1)
  2589.                     strcat(ss, " ");
  2590.             }
  2591.         }
  2592.     }
  2593.  
  2594.     if (!multmatch || mode == -1 || mode == 4)
  2595.     {
  2596.         FreeWild(cmd_numfiles, cmd_files);
  2597.         cmd_numfiles = -1;
  2598.     }
  2599.     return ss;
  2600. }
  2601.  
  2602. /*
  2603.  * show all filenames that match the string "file" with length "len"
  2604.  */
  2605.     static void
  2606. showmatches(file, len)
  2607.     char *file;
  2608.     int    len;
  2609. {
  2610.     char *file_str;
  2611.     int num_files;
  2612.     char **files_found;
  2613.     int i, j, k;
  2614.     int maxlen;
  2615.     int lines;
  2616.     int columns;
  2617.  
  2618.     file_str = addstar(file, len);        /* add star to file name */
  2619.     if (file_str != NULL)
  2620.     {
  2621.         outchar('\n');
  2622.         flushbuf();
  2623.  
  2624.         /* find all files that match the description */
  2625.         ExpandWildCards(1, &file_str, &num_files, &files_found, FALSE, FALSE);
  2626.  
  2627.         /* find the maximum length of the file names */
  2628.         maxlen = 0;
  2629.         for (i = 0; i < num_files; ++i)
  2630.         {
  2631.             j = strlen(files_found[i]);
  2632.             if (j > maxlen)
  2633.                 maxlen = j;
  2634.         }
  2635.  
  2636.         /* compute the number of columns and lines for the listing */
  2637.         maxlen += 2;    /* two spaces between file names */
  2638.         columns = ((int)Columns + 2) / maxlen;
  2639.         if (columns < 1)
  2640.             columns = 1;
  2641.         lines = (num_files + columns - 1) / columns;
  2642.  
  2643.         /* list the files line by line */
  2644. #ifdef AMIGA
  2645.         settmode(0);        /* allow output to be halted */
  2646. #endif
  2647.         for (i = 0; i < lines; ++i)
  2648.         {
  2649.             for (k = i; k < num_files; k += lines)
  2650.             {
  2651.                 if (k > i)
  2652.                     for (j = maxlen - strlen(files_found[k - lines]); --j >= 0; )
  2653.                         outchar(' ');
  2654.                 j = isdir(files_found[k]);    /* highlight directories */
  2655.                 if (j > 0)
  2656.                 {
  2657. #ifdef AMIGA
  2658.                     if (term_console)
  2659.                         outstr("\033[33m");        /* use highlight color */
  2660.                     else
  2661. #endif /* AMIGA */
  2662.                         outstr(T_TI);
  2663.                 }
  2664.                 outstrn(files_found[k]);
  2665.                 if (j > 0)
  2666.                 {
  2667. #ifdef AMIGA
  2668.                     if (term_console)
  2669.                         outstr("\033[0m");        /* use normal color */
  2670.                     else
  2671. #endif /* AMIGA */
  2672.                         outstr(T_TP);
  2673.                 }
  2674.             }
  2675.             outchar('\n');
  2676.             flushbuf();
  2677.         }
  2678.         free(file_str);
  2679.         FreeWild(num_files, files_found);
  2680. #ifdef AMIGA
  2681.         settmode(1);
  2682. #endif
  2683.  
  2684.         for (i = cmdoffset; --i >= 0; )    /* make room for the command */
  2685.             outchar('\n');
  2686.         must_redraw = CLEAR;            /* must redraw later */
  2687.     }
  2688. }
  2689.  
  2690. /*
  2691.  * copy the file name into allocated memory and add a '*' at the end
  2692.  */
  2693.     static char *
  2694. addstar(fname, len)
  2695.     char    *fname;
  2696.     int        len;
  2697. {
  2698.     char    *retval;
  2699. #ifdef MSDOS
  2700.     int        i;
  2701. #endif
  2702.  
  2703.     retval = alloc(len + 4);
  2704.     if (retval != NULL)
  2705.     {
  2706.         strncpy(retval, fname, (size_t)len);
  2707. #ifdef MSDOS
  2708.     /*
  2709.      * if there is no dot in the file name, add "*.*" instead of "*".
  2710.      */
  2711.         for (i = len - 1; i >= 0; --i)
  2712.             if (strchr(".\\/:", retval[i]))
  2713.                 break;
  2714.         if (i < 0 || retval[i] != '.')
  2715.         {
  2716.             retval[len++] = '*';
  2717.             retval[len++] = '.';
  2718.         }
  2719. #endif
  2720.         retval[len] = '*';
  2721.         retval[len + 1] = 0;
  2722.     }
  2723.     return retval;
  2724. }
  2725.  
  2726. /*
  2727.  * dosource: read the file "fname" and execute its lines as EX commands
  2728.  *
  2729.  * This function may be called recursively!
  2730.  */
  2731.     int
  2732. dosource(fname)
  2733.     register char *fname;
  2734. {
  2735.     register FILE    *fp;
  2736.     register int    len;
  2737. #ifdef MSDOS
  2738.     int                error = FALSE;
  2739. #endif
  2740.  
  2741.     expand_env(fname, IObuff, IOSIZE);        /* use IObuff for expanded name */
  2742.     if ((fp = fopen(IObuff, READBIN)) == NULL)
  2743.         return 1;
  2744.  
  2745.     len = 0;
  2746.     while (fgets(IObuff + len, IOSIZE - len, fp) != NULL && !got_int)
  2747.     {
  2748.         len = strlen(IObuff) - 1;
  2749.         if (len >= 0 && IObuff[len] == '\n')    /* remove trailing newline */
  2750.         {
  2751.                 /* escaped newline, read more */
  2752.             if (len > 0 && len < IOSIZE && IObuff[len - 1] == Ctrl('V'))
  2753.             {
  2754.                 IObuff[len - 1] = '\n';        /* remove CTRL-V */
  2755.                 continue;
  2756.             }
  2757. #ifdef MSDOS
  2758.             if (len > 0 && IObuff[len - 1] == '\r') /* trailing CR-LF */
  2759.                 --len;
  2760.             else
  2761.             {
  2762.                 if (!error)
  2763.                     emsg("Warning: Wrong line separator, ^M may be missing");
  2764.                 error = TRUE;        /* lines like ":map xx yy^M" will fail */
  2765.             }
  2766. #endif
  2767.             IObuff[len] = NUL;
  2768.         }
  2769.         breakcheck();        /* check for ^C here, so recursive :so will be broken */
  2770.         docmdline((u_char *)IObuff);
  2771.         len = 0;
  2772.     }
  2773.     fclose(fp);
  2774.     if (got_int)
  2775.         emsg(e_interr);
  2776.     return 0;
  2777. }
  2778.  
  2779. /*
  2780.  * get single EX address
  2781.  */
  2782.     static linenr_t
  2783. get_address(ptr)
  2784.     u_char        **ptr;
  2785. {
  2786.     linenr_t    curpos_lnum = Curpos.lnum;
  2787.     int            c;
  2788.     int            i;
  2789.     long        n;
  2790.     u_char      *cmd;
  2791.     FPOS        pos;
  2792.     FPOS        *fp;
  2793.     linenr_t    lnum;
  2794.  
  2795.     cmd = *ptr;
  2796.     skipspace((char **)&cmd);
  2797.     lnum = INVLNUM;
  2798.     do
  2799.     {
  2800.         switch (*cmd)
  2801.         {
  2802.             case '.':                         /* '.' - Cursor position */
  2803.                         ++cmd;
  2804.                         lnum = curpos_lnum;
  2805.                         break;
  2806.  
  2807.             case '$':                         /* '$' - last line */
  2808.                         ++cmd;
  2809.                         lnum = line_count;
  2810.                         break;
  2811.  
  2812.             case '\'':                         /* ''' - mark */
  2813.                         if (*++cmd == NUL || (fp = getmark(*cmd++, FALSE)) == NULL)
  2814.                         {
  2815.                             emsg(e_umark);
  2816.                             goto error;
  2817.                         }
  2818.                         lnum = fp->lnum;
  2819.                         break;
  2820.  
  2821.             case '/':
  2822.             case '?':                        /* '/' or '?' - search */
  2823.                         c = *cmd++;
  2824.                         pos = Curpos;        /* save Curpos */
  2825.                         Curpos.col = -1;    /* searchit() will increment the col */
  2826.                         if (c == '/')
  2827.                         {
  2828.                              if (Curpos.lnum == line_count)    /* :/pat on last line */
  2829.                                 Curpos.lnum = 1;
  2830.                             else
  2831.                                 ++Curpos.lnum;
  2832.                         }
  2833.                         searchcmdlen = 0;
  2834.                         if (dosearch(c, (char *)cmd, FALSE, (long)1, FALSE))
  2835.                             lnum = Curpos.lnum;
  2836.                         Curpos = pos;
  2837.                 
  2838.                         cmd += searchcmdlen;    /* adjust command string pointer */
  2839.                         break;
  2840.  
  2841.             default:
  2842.                         if (isdigit(*cmd))                /* absolute line number */
  2843.                             lnum = getdigits((char **)&cmd);
  2844.         }
  2845.         
  2846.         while (*cmd == '-' || *cmd == '+')
  2847.         {
  2848.             if (lnum == INVLNUM)
  2849.                 lnum = curpos_lnum;
  2850.             i = *cmd++;
  2851.             if (!isdigit(*cmd))    /* '+' is '+1', but '+0' is not '+1' */
  2852.                 n = 1;
  2853.             else 
  2854.                 n = getdigits((char **)&cmd);
  2855.             if (i == '-')
  2856.                 lnum -= n;
  2857.             else
  2858.                 lnum += n;
  2859.         }
  2860.  
  2861.         curpos_lnum = lnum;
  2862.     } while (*cmd == '/' || *cmd == '?');
  2863.  
  2864. error:
  2865.     *ptr = cmd;
  2866.     return lnum;
  2867. }
  2868.  
  2869. /*
  2870.  * align text:
  2871.  * type = -1  left aligned
  2872.  * type = 0   centered
  2873.  * type = 1   right aligned
  2874.  */
  2875.     static void
  2876. do_align(start, end, width, type)
  2877.     linenr_t    start;
  2878.     linenr_t    end;
  2879.     int            width;
  2880.     int            type;
  2881. {
  2882.     FPOS    pos;
  2883.     int        len;
  2884.     int        indent = 0;
  2885.  
  2886.     pos = Curpos;
  2887.     if (type == -1)        /* left align: width is used for new indent */
  2888.     {
  2889.         if (width >= 0)
  2890.             indent = width;
  2891.     }
  2892.     else
  2893.     {
  2894.         if (width <= 0)
  2895.             width = p_tw;
  2896.         if (width == 0)
  2897.             width = 80;
  2898.     }
  2899.  
  2900.     if (!u_save((linenr_t)(line1 - 1), (linenr_t)(line2 + 1)))
  2901.         return;
  2902.     for (Curpos.lnum = start; Curpos.lnum <= end; ++Curpos.lnum)
  2903.     {
  2904.         set_indent(indent, TRUE);                /* remove existing indent */
  2905.         if (type == -1)                            /* left align */
  2906.             continue;
  2907.         len = strsize(nr2ptr(Curpos.lnum));        /* get line lenght */
  2908.         if (len < width)
  2909.             switch (type)
  2910.             {
  2911.             case 0:        set_indent((width - len) / 2, FALSE);    /* center */
  2912.                         break;
  2913.             case 1:        set_indent(width - len, FALSE);            /* right */
  2914.                         break;
  2915.             }
  2916.     }
  2917.     Curpos = pos;
  2918.     beginline(TRUE);
  2919.     updateScreen(NOT_VALID);
  2920. }
  2921.