home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / pvic_10a.lzh / SRCE / cmdline.c < prev    next >
Text File  |  1998-06-09  |  13KB  |  686 lines

  1. /* 
  2.  *
  3.  * Routines to parse and execute "command line" commands, such as searches
  4.  * or colon commands.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include "pvic.h"
  9. #include "locdefs.h"
  10.  
  11. static  char    *altfile = NULL;        /* alternate file */
  12. static  int     altline;                /* line # in alternate file */
  13.  
  14. static  char    *nowrtmsg = "No write since last change (use '!' to override)";
  15. static  char    *nooutfile = "No output file";
  16. static  char    *morefiles = "More files to edit";
  17.  
  18. extern  char    **files;                /* used for "n" and "rew" */
  19. extern  int     number_of_files, current_file;
  20.  
  21. #define CMDSZ   100             /* size of the command buffer */
  22.  
  23. static  void    get_range();
  24. static  LPTR    *get_line();
  25.  
  26. void do_exit();
  27.  
  28. /*
  29.  * getcmdln() - read a command line from the terminal
  30.  *
  31.  * Reads a command line started by typing '/', '?', '!', or ':'. Returns a
  32.  * pointer to the string that was read. For searches, an optional trailing
  33.  * '/' or '?' is removed.
  34.  */
  35. char *getcmdln(firstc)
  36. char    firstc;
  37. {
  38.     static  char    buff[CMDSZ];
  39.     register char   *p = buff;
  40.     register int    c;
  41.     register char   *q;
  42.  
  43.     update_screen(1);
  44.     goto_command((1), firstc);
  45.  
  46.     /* collect the command string, handling '\b' and @ */
  47.     do {
  48.         switch (c = get_char_from_input_buffer()) {
  49.  
  50.             default:            /* a normal character */
  51.             putc(c,stdout);
  52.             *p++ = c;
  53.             break;
  54.  
  55.             case CTRL_H:
  56.             if (p > buff) {
  57.                 /*
  58.                  * this is gross, but it relies
  59.                  * only on 'goto_command'
  60.                  */
  61.                 p--;
  62.                 goto_command((1), firstc);
  63.                 for (q = buff; q < p ;q++)
  64.                     putc(*q,stdout);
  65.             } else {
  66.                 msg("");
  67.                 return NULL;            /* back to cmd mode */
  68.             }
  69.             break;
  70.  
  71.             case '@':                   /* line kill */
  72.             p = buff;
  73.             goto_command((1), firstc);
  74.             break;
  75.  
  76.             case ESC:           /* abandon command */
  77.             msg("");
  78.             return  NULL;
  79.  
  80.             case CTRL_J:                /* done reading the line */
  81.             case CTRL_M:
  82.             break;
  83.         }
  84.     } while (c != CTRL_J && c != CTRL_M);
  85.  
  86.     *p = '\0';
  87.  
  88.     if (firstc == '/' || firstc == '?') {   /* did we do a search? */
  89.         /*
  90.          * Look for a terminating '/' or '?'. This will be the first
  91.          * one that isn't quoted. Truncate the search string there.
  92.          */
  93.         for (p = buff; *p ;) {
  94.             if (*p == firstc) {     /* we're done */
  95.                 *p = '\0';
  96.                 break;
  97.             } else if (*p == '\\')  /* next char quoted */
  98.                 p += 2;
  99.             else
  100.                 p++;            /* normal char */
  101.         }
  102.     }
  103.     return buff;
  104. }
  105.  
  106. /*
  107.  * do_command_line() - handle a colon command
  108.  *
  109.  * Handles a colon command received interactively by getcmdln() or from
  110.  * the environment variable "EXINIT" (or eventually .virc).
  111.  */
  112. void do_command_line(cmdline)
  113. char    *cmdline;
  114. {
  115.     char    buff[CMDSZ];
  116.     char    cmdbuf[CMDSZ];
  117.     char    argbuf[CMDSZ];
  118.     char    *cmd, *arg;
  119.     register char   *p;
  120.     /*
  121.      * The next two variables contain the bounds of any range given in a
  122.      * command. If no range was given, both contain null line pointers.
  123.      * If only a single line was given, u_pos will contain a null line
  124.      * pointer.
  125.      */
  126.     LPTR    l_pos, u_pos;
  127.  
  128.  
  129.     /*
  130.      * Clear the range variables.
  131.      */
  132.     l_pos.linep = (struct line *) NULL;
  133.     u_pos.linep = (struct line *) NULL;
  134.  
  135.     if (cmdline == NULL)
  136.         return;
  137.  
  138.     if (strlen(cmdline) > CMDSZ-2) {
  139.         msg("Command line too long");
  140.         return;
  141.     }
  142.     strcpy(buff, cmdline);
  143.  
  144.     /* skip any initial white space */
  145.     for (cmd = buff; *cmd != '\0' && is_space(*cmd) ;cmd++)
  146.         ;
  147.  
  148.     if (*cmd == '%') {              /* change '%' to "1,$" */
  149.         strcpy(cmdbuf, "1,$");  /* kind of gross... */
  150.         strcat(cmdbuf, cmd+1);
  151.         strcpy(cmd, cmdbuf);
  152.     }
  153.  
  154.     while ((p=get_pointer_to_chr_in_string(cmd, '%')) != NULL
  155.            && *(p-1) != '\\')
  156.     {
  157.         /*
  158.             change '%' to file_name
  159.         */
  160.         if (file_name == NULL) {
  161.             error_message("No filename");
  162.             return;
  163.         }
  164.         *p= '\0';
  165.         strcpy (cmdbuf, cmd);
  166.         strcat (cmdbuf, file_name);
  167.         strcat (cmdbuf, p+1);
  168.         strcpy(cmd, cmdbuf);
  169.         msg(cmd);                       /*repeat */
  170.     }
  171.  
  172.     while ((p=get_pointer_to_chr_in_string(cmd, '#')) != NULL
  173.            && *(p-1) != '\\')
  174.     {
  175.         /*
  176.             change '#' to Altname
  177.         */
  178.         if (altfile == NULL) {
  179.             error_message("No alternate file");
  180.             return;
  181.         }
  182.         *p= '\0';
  183.         strcpy (cmdbuf, cmd);
  184.         strcat (cmdbuf, altfile);
  185.         strcat (cmdbuf, p+1);
  186.         strcpy(cmd, cmdbuf);
  187.         msg(cmd);                       /*repeat */
  188.     }
  189.  
  190.     /*
  191.      * Parse a range, if present (and update the cmd pointer).
  192.      */
  193.     get_range(&cmd, &l_pos, &u_pos);
  194.  
  195.     if (l_pos.linep != NULL)
  196.     {
  197.         if (LINEOF(&l_pos) > LINEOF(&u_pos))
  198.         {
  199.             error_message("Invalid range");
  200.             return;
  201.         }
  202.     }
  203.  
  204.     strcpy(cmdbuf, cmd);    /* save the unmodified command */
  205.  
  206.     /*
  207.         isolate the command and find any argument
  208.     */
  209.     for ( p=cmd; *p != '\0' && ! is_space(*p); p++ )
  210.         ;
  211.  
  212.     if ( *p == '\0' )
  213.         arg = NULL;
  214.     else
  215.     {
  216.         *p = '\0';
  217.         for (p++; *p != '\0' && is_space(*p) ;p++)
  218.             ;
  219.         if (*p == '\0')
  220.             arg = NULL;
  221.         else
  222.         {
  223.             strcpy(argbuf, p);
  224.             arg = argbuf;
  225.         }
  226.     }
  227.     if (strcmp(cmd,"q!") == 0)
  228.         get_out();
  229.     if (strcmp(cmd,"q") == 0)
  230.     {
  231.         if (changed)
  232.             error_message(nowrtmsg);
  233.         else
  234.         {
  235.             if ((current_file + 1) < number_of_files)
  236.                 error_message(morefiles);
  237.             else
  238.                 get_out();
  239.         }
  240.         return;
  241.     }
  242.     if (strcmp(cmd,"w") == 0)
  243.     {
  244.         if (arg == NULL)
  245.         {
  246.             if (file_name != NULL)
  247.             {
  248.                 write_it(file_name, &l_pos, &u_pos);
  249.             }
  250.             else
  251.                 error_message(nooutfile);
  252.         }
  253.         else
  254.             write_it(arg, &l_pos, &u_pos);
  255.         return;
  256.     }
  257.     if (strcmp(cmd,"wq") == 0)
  258.     {
  259.         if (file_name != NULL)
  260.         {
  261.             if (write_it(file_name, (LPTR *)NULL, (LPTR *)NULL))
  262.                 get_out();
  263.         }
  264.         else
  265.             error_message(nooutfile);
  266.         return;
  267.     }
  268.     if (strcmp(cmd, "x") == 0) {
  269.         do_exit();
  270.         return;
  271.     }
  272.  
  273.     if (strcmp(cmd,"f") == 0 && arg == NULL) {
  274.         file_info();
  275.         return;
  276.     }
  277.     if (*cmd == 'n') {
  278.         if ((current_file + 1) < number_of_files) {
  279.             /*
  280.              * stuff ":e[!] FILE\n"
  281.              */
  282.             put_string_into_input_buffer(":e");
  283.             if (cmd[1] == '!')
  284.                 put_string_into_input_buffer("!");
  285.             put_string_into_input_buffer(" ");
  286.             put_string_into_input_buffer(files[++current_file]);
  287.             put_string_into_input_buffer("\n");
  288.         } else
  289.             error_message("No more files");
  290.         return;
  291.     }
  292.     if (*cmd == 'N') {
  293.         if (current_file > 0) {
  294.             /*
  295.              * stuff ":e[!] FILE\n"
  296.              */
  297.             put_string_into_input_buffer(":e");
  298.             if (cmd[1] == '!')
  299.                 put_string_into_input_buffer("!");
  300.             put_string_into_input_buffer(" ");
  301.             put_string_into_input_buffer(files[--current_file]);
  302.             put_string_into_input_buffer("\n");
  303.         } else
  304.             error_message("No more files");
  305.         return;
  306.     }
  307.     if (strncmp(cmd, "rew", 3) == 0) {
  308.         if (number_of_files <= 1)                /* nothing to rewind */
  309.             return;
  310.         current_file = 0;
  311.         /*
  312.          * stuff ":e[!] FILE\n"
  313.          */
  314.         put_string_into_input_buffer(":e");
  315.         if (cmd[3] == '!')
  316.             put_string_into_input_buffer("!");
  317.         put_string_into_input_buffer(" ");
  318.         put_string_into_input_buffer(files[0]);
  319.         put_string_into_input_buffer("\n");
  320.         return;
  321.     }
  322.     if (strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0) {
  323.         (void) do_e_command(arg, cmd[1] == '!');
  324.         return;
  325.     }
  326.     /*
  327.      * The command ":e#" gets expanded to something like ":efile", so
  328.      * detect that case here.
  329.      */
  330.     if (*cmd == 'e' && arg == NULL) {
  331.         if (cmd[1] == '!')
  332.             (void) do_e_command(&cmd[2], (1));
  333.         else
  334.             (void) do_e_command(&cmd[1], (0));
  335.         return;
  336.     }
  337.     if (strcmp(cmd,"f") == 0) {
  338.         eval_environment (arg, CMDSZ);   /* expand environment vars */
  339.         file_name = strsave(arg);
  340.         file_message("");
  341.         return;
  342.     }
  343.     if (strcmp(cmd,"r") == 0) {
  344.         if (arg == NULL) {
  345.             bad_command();
  346.             return;
  347.         }
  348.         if (read_file(arg, cursor_char, 1)) {
  349.             error_message("Can't open file");
  350.             return;
  351.         }
  352.         update_screen(1);
  353.         CHANGED;
  354.         return;
  355.     }
  356.     if (strcmp(cmd,"=") == 0) {
  357.         show_message("%d", cntllines(file_memory, &l_pos));
  358.         return;
  359.     }
  360.     if (strncmp(cmd,"set", 2) == 0) {
  361.         do_set(arg);
  362.         return;
  363.     }
  364.     if (strcmp(cmd,"help") == 0) {
  365.         if(help()==0)
  366.         {
  367.             clear_screen();
  368.             update_screen(0);
  369.         }
  370.         else error_message("No help available");
  371.         return;
  372.     }
  373.     if (strncmp(cmd, "ve", 2) == 0) {
  374.         msg(VERSION_STRING);
  375.         return;
  376.     }
  377.     if (strcmp(cmd, "sh") == 0) {
  378.         do_shell(NULL);
  379.         return;
  380.     }
  381.     if (*cmd == '!') {
  382.         do_shell(cmdbuf+1);
  383.         return;
  384.     }
  385.     if (strncmp(cmd, "s/", 2) == 0) {
  386.         do_sub(&l_pos, &u_pos, cmdbuf+1);
  387.         return;
  388.     }
  389.     if (strncmp(cmd, "g/", 2) == 0) {
  390.         do_glob(&l_pos, &u_pos, cmdbuf+1);
  391.         return;
  392.     }
  393.     if (strcmp(cmd, "j") == 0) {
  394.         do_join(1);
  395.         update_screen(0);
  396.         return;
  397.     }
  398.     
  399.     /*
  400.      * If we got a line, but no command, then go to the line.
  401.      */
  402.     if (*cmd == '\0' && l_pos.linep != NULL) {
  403.         *cursor_char = l_pos;
  404.         return;
  405.     }
  406.  
  407.     bad_command();
  408. }
  409.  
  410.  
  411. void do_exit()        /* v1.1 */
  412. {
  413.     if (changed) {
  414.         if (file_name != NULL) {
  415.             if (!write_it(file_name, (LPTR *)NULL, (LPTR *)NULL))
  416.                 return;
  417.         } else {
  418.             error_message(nooutfile);
  419.             return;
  420.         }
  421.     }
  422.     if ((current_file + 1) < number_of_files)
  423.         error_message(morefiles);
  424.     else
  425.         get_out();
  426. }
  427.  
  428. /*
  429.  * get_range - parse a range specifier
  430.  *
  431.  * Ranges are of the form:
  432.  *
  433.  * addr[,addr]
  434.  *
  435.  * where 'addr' is:
  436.  *
  437.  * $  [+- NUM]
  438.  * 'x [+- NUM]  (where x denotes a currently defined mark)
  439.  * .  [+- NUM]
  440.  * [+- NUM]        (short cut on .+- NUM implemented by real vi)
  441.  * NUM
  442.  *
  443.  * The pointer *cp is updated to point to the first character following
  444.  * the range spec. If an initial address is found, but no second, the
  445.  * upper bound is equal to the lower.
  446.  */
  447. static void get_range(cp, lower, upper)
  448. register char   **cp;
  449. LPTR    *lower, *upper;
  450. {
  451.     register LPTR   *l;
  452.     register char   *p;
  453.  
  454.     if ((l = get_line(cp)) == NULL)
  455.         return;
  456.  
  457.     *lower = *l;
  458.  
  459.     for (p = *cp; *p != '\0' && is_space(*p) ;p++)
  460.         ;
  461.  
  462.     *cp = p;
  463.  
  464.     if (*p != ',') {                /* is there another line spec ? */
  465.         *upper = *lower;
  466.         return;
  467.     }
  468.  
  469.     *cp = ++p;
  470.  
  471.     if ((l = get_line(cp)) == NULL) {
  472.         *upper = *lower;
  473.         return;
  474.     }
  475.  
  476.     *upper = *l;
  477. }
  478.  
  479. static LPTR *get_line(cp)
  480. char    **cp;
  481. {
  482.     static  LPTR    pos;
  483.     LPTR    *lp;
  484.     register char   *p, c;
  485.     register int    lnum;
  486.     int                neg;
  487.  
  488.     pos.index = 0;          /* shouldn't matter... check back later */
  489.  
  490.     p = *cp;
  491.     /*
  492.      * Determine the basic form, if present.
  493.      */
  494.     switch (c = *p++) {
  495.  
  496.     case '$':
  497.         pos.linep = end_of_file->linep->prev;
  498.         break;
  499.  
  500.     case '.':
  501.         pos.linep = cursor_char->linep;
  502.         break;
  503.  
  504.     case '-':
  505.     case '+':
  506.         pos.linep = cursor_char->linep;
  507.         neg = (c == '-');
  508.     
  509.         for (lnum = 0; is_digit(*p) ;p++)
  510.             lnum = (lnum * 10) + (*p - '0');
  511.  
  512.         if (neg)
  513.             lnum = -lnum;
  514.  
  515.         pos = *goto_line( cntllines(file_memory, &pos) + lnum );
  516.  
  517.         break;
  518.     
  519.     case '\'':
  520.         if ((lp = get_mark(*p++)) == NULL) {
  521.             error_message("Unknown mark");
  522.             return (LPTR *) NULL;
  523.         }
  524.         pos = *lp;
  525.         break;
  526.  
  527.     case '0': case '1': case '2': case '3': case '4':
  528.     case '5': case '6': case '7': case '8': case '9':
  529.         for (lnum = c - '0'; is_digit(*p) ;p++)
  530.             lnum = (lnum * 10) + (*p - '0');
  531.  
  532.         pos = *goto_line(lnum);
  533.         break;
  534.  
  535.     default:
  536.         return (LPTR *) NULL;
  537.     }
  538.  
  539.     while (*p != '\0' && is_space(*p))
  540.         p++;
  541.  
  542.     if (*p == '-' || *p == '+')
  543.     {
  544.         neg = (*p++ == '-');
  545.  
  546.         for (lnum = 0; is_digit(*p) ;p++)
  547.             lnum = (lnum * 10) + (*p - '0');
  548.  
  549.         if (neg)
  550.             lnum = -lnum;
  551.  
  552.         pos = *goto_line( cntllines(file_memory, &pos) + lnum );
  553.     }
  554.  
  555.     *cp = p;
  556.     return &pos;
  557. }
  558.  
  559. void bad_command()
  560. {
  561.     error_message("Unrecognized command");
  562. }
  563.  
  564. int do_e_command(arg, force)
  565. char    *arg;
  566. int     force;
  567. {
  568.     int     line = 1;               /* line # to go to in new file */
  569.  
  570.     if (!force && changed) {
  571.         error_message(nowrtmsg);
  572.         if (altfile)
  573.             free(altfile);
  574.         altfile = strsave(arg);
  575.         return (0);
  576.     }
  577.     if (arg != NULL) {
  578.         /*
  579.          * First detect a ":e" on the current file. This is mainly
  580.          * for ":ta" commands where the destination is within the
  581.          * current file.
  582.          */
  583.         if (file_name != NULL && strcmp(arg, file_name) == 0) {
  584.             if (!changed || (changed && !force))
  585.                 return (1);
  586.         }
  587.         if (altfile) {
  588.             if (strcmp (arg, altfile) == 0)
  589.                 line = altline;
  590.             free(altfile);
  591.         }
  592.         altfile = file_name;
  593.         altline = cntllines(file_memory, cursor_char);
  594.         file_name = strsave(arg);
  595.     }
  596.     if (file_name == NULL) {
  597.         error_message("No filename");
  598.         return (0);
  599.     }
  600.  
  601.     /* clear mem and read file */
  602.     freeall();
  603.     file_alloc();
  604.     UNCHANGED;
  605.  
  606.     if (read_file(file_name, file_memory, 0))
  607.         file_message("[New File]");
  608.  
  609.     *top_char = *cursor_char;
  610.     if (line != 1) {
  611.         put_int_into_input_buffer(line);
  612.         put_string_into_input_buffer("G");
  613.     }
  614.     set_pc_mark();
  615.     update_screen(0);
  616.     return (1);
  617. }
  618.  
  619. void goto_command(clr, firstc)
  620. int  clr;
  621. char    firstc;
  622. {
  623.     goto_screen_pos(current_lines-1,0);
  624.     if (clr)termcap_out(termcap_clr_eol); /* clear the bottom line */
  625.     if (firstc)
  626.         putc(firstc,stdout);
  627. }
  628.  
  629. /*
  630.  * msg(s) - displays the string 's' on the status line
  631.  */
  632. void msg(s)
  633. char    *s;
  634. {
  635.     goto_command((1), 0);
  636.     fprintf(stdout,"%s",s);
  637.     fflush(stdout);
  638. }
  639.  
  640. /*VARARGS1*/
  641. void show_message(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)
  642. char    *s;
  643. int     a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16;
  644. {
  645.     char    sbuf[80];
  646.  
  647.     sprintf(sbuf, s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16);
  648.     msg(sbuf);
  649. }
  650.  
  651. /*
  652.  * error_message() - display an error message
  653.  *
  654.  * Rings the bell, if appropriate, and calls message() to do the real work
  655.  */
  656. void error_message(s)
  657. char    *s;
  658. {
  659.     if (PARAMETER_VALUE(PARAMETER_ERRORBELLS))
  660.         beep();
  661.     msg(s);
  662. }
  663.  
  664. void wait_return()
  665. {
  666.     register char   c;
  667.  
  668.     if(local_control_c_pressed())fprintf(stdout,"%s","Interrupt   ");
  669.  
  670.     fprintf(stdout,"Press RETURN to continue");
  671.     do 
  672.     {
  673.         c = get_char_from_input_buffer();
  674.     } 
  675.     while (c != CTRL_J && c != CTRL_M && c != ' ' && c != ':');
  676.  
  677.     if (c == ':') 
  678.     {
  679.         putc('\n',stdout);
  680.         do_command_line(getcmdln(c));
  681.     } 
  682.     else clear_screen();
  683.  
  684.     update_screen(0);
  685. }
  686.