home *** CD-ROM | disk | FTP | other *** search
/ Der Mediaplex Sampler - Die 6 von Plex / 6_v_plex.zip / 6_v_plex / DISK5 / DOS_50 / PVIC.ZIP / CMDLINE.C < prev    next >
C/C++ Source or Header  |  1993-04-21  |  14KB  |  638 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 && *(p-1) != '\\') {
  155.                     /* change '%' to file_name */
  156.         if (file_name == NULL) {
  157.             error_message("No filename");
  158.             return;
  159.         }
  160.         *p= '\0';
  161.         strcpy (cmdbuf, cmd);
  162.         strcat (cmdbuf, file_name);
  163.         strcat (cmdbuf, p+1);
  164.         strcpy(cmd, cmdbuf);
  165.         msg(cmd);                       /*repeat */
  166.     }
  167.  
  168.     while ((p=get_pointer_to_chr_in_string(cmd, '#')) != NULL && *(p-1) != '\\') {
  169.                     /* change '#' to Altname */
  170.         if (altfile == NULL) {
  171.             error_message("No alternate file");
  172.             return;
  173.         }
  174.         *p= '\0';
  175.         strcpy (cmdbuf, cmd);
  176.         strcat (cmdbuf, altfile);
  177.         strcat (cmdbuf, p+1);
  178.         strcpy(cmd, cmdbuf);
  179.         msg(cmd);                       /*repeat */
  180.     }
  181.  
  182.     /*
  183.      * Parse a range, if present (and update the cmd pointer).
  184.      */
  185.     get_range(&cmd, &l_pos, &u_pos);
  186.  
  187.     if (l_pos.linep != NULL) {
  188.         if (LINEOF(&l_pos) > LINEOF(&u_pos)) {
  189.             error_message("Invalid range");
  190.             return;
  191.         }
  192.     }
  193.  
  194.     strcpy(cmdbuf, cmd);    /* save the unmodified command */
  195.  
  196.     /* isolate the command and find any argument */
  197.     for ( p=cmd; *p != '\0' && ! is_space(*p); p++ )
  198.         ;
  199.     if ( *p == '\0' )
  200.         arg = NULL;
  201.     else {
  202.         *p = '\0';
  203.         for (p++; *p != '\0' && is_space(*p) ;p++)
  204.             ;
  205.         if (*p == '\0')
  206.             arg = NULL;
  207.         else {
  208.             strcpy(argbuf, p);
  209.             arg = argbuf;
  210.         }
  211.     }
  212.     if (strcmp(cmd,"q!") == 0)
  213.         get_out();
  214.     if (strcmp(cmd,"q") == 0) {
  215.         if (changed)
  216.             error_message(nowrtmsg);
  217.         else {
  218.             if ((current_file + 1) < number_of_files)
  219.                 error_message(morefiles);
  220.             else
  221.                 get_out();
  222.         }
  223.         return;
  224.     }
  225.     if (strcmp(cmd,"w") == 0) {
  226.         if (arg == NULL) {
  227.             if (file_name != NULL) {
  228.                 write_it(file_name, &l_pos, &u_pos);
  229.             } else
  230.                 error_message(nooutfile);
  231.         }
  232.         else
  233.             write_it(arg, &l_pos, &u_pos);
  234.         return;
  235.     }
  236.     if (strcmp(cmd,"wq") == 0) {
  237.         if (file_name != NULL) {
  238.             if (write_it(file_name, (LPTR *)NULL, (LPTR *)NULL))
  239.                 get_out();
  240.         } else
  241.             error_message(nooutfile);
  242.         return;
  243.     }
  244.     if (strcmp(cmd, "x") == 0) {
  245.         do_exit();
  246.         return;
  247.     }
  248.  
  249.     if (strcmp(cmd,"f") == 0 && arg == NULL) {
  250.         file_info();
  251.         return;
  252.     }
  253.     if (*cmd == 'n') {
  254.         if ((current_file + 1) < number_of_files) {
  255.             /*
  256.              * stuff ":e[!] FILE\n"
  257.              */
  258.             put_string_into_input_buffer(":e");
  259.             if (cmd[1] == '!')
  260.                 put_string_into_input_buffer("!");
  261.             put_string_into_input_buffer(" ");
  262.             put_string_into_input_buffer(files[++current_file]);
  263.             put_string_into_input_buffer("\n");
  264.         } else
  265.             error_message("No more files");
  266.         return;
  267.     }
  268.     if (*cmd == 'N') {
  269.         if (current_file > 0) {
  270.             /*
  271.              * stuff ":e[!] FILE\n"
  272.              */
  273.             put_string_into_input_buffer(":e");
  274.             if (cmd[1] == '!')
  275.                 put_string_into_input_buffer("!");
  276.             put_string_into_input_buffer(" ");
  277.             put_string_into_input_buffer(files[--current_file]);
  278.             put_string_into_input_buffer("\n");
  279.         } else
  280.             error_message("No more files");
  281.         return;
  282.     }
  283.     if (strncmp(cmd, "rew", 3) == 0) {
  284.         if (number_of_files <= 1)              /* nothing to rewind */
  285.             return;
  286.         current_file = 0;
  287.         /*
  288.          * stuff ":e[!] FILE\n"
  289.          */
  290.         put_string_into_input_buffer(":e");
  291.         if (cmd[3] == '!')
  292.             put_string_into_input_buffer("!");
  293.         put_string_into_input_buffer(" ");
  294.         put_string_into_input_buffer(files[0]);
  295.         put_string_into_input_buffer("\n");
  296.         return;
  297.     }
  298.     if (strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0) {
  299.         (void) do_e_command(arg, cmd[1] == '!');
  300.         return;
  301.     }
  302.     /*
  303.      * The command ":e#" gets expanded to something like ":efile", so
  304.      * detect that case here.
  305.      */
  306.     if (*cmd == 'e' && arg == NULL) {
  307.         if (cmd[1] == '!')
  308.             (void) do_e_command(&cmd[2], (1));
  309.         else
  310.             (void) do_e_command(&cmd[1], (0));
  311.         return;
  312.     }
  313.     if (strcmp(cmd,"f") == 0) {
  314.         eval_environment (arg, CMDSZ);   /* expand environment vars */
  315.         file_name = strsave(arg);
  316.         file_message("");
  317.         return;
  318.     }
  319.     if (strcmp(cmd,"r") == 0) {
  320.         if (arg == NULL) {
  321.             bad_command();
  322.             return;
  323.         }
  324.         if (read_file(arg, cursor_char, 1)) {
  325.             error_message("Can't open file");
  326.             return;
  327.         }
  328.         update_screen(1);
  329.         CHANGED;
  330.         return;
  331.     }
  332.     if (strcmp(cmd,"=") == 0) {
  333.         show_message("%d", cntllines(file_memory, &l_pos));
  334.         return;
  335.     }
  336.     if (strncmp(cmd,"set", 2) == 0) {
  337.         do_set(arg);
  338.         return;
  339.     }
  340.     if (strcmp(cmd,"help") == 0) {
  341.         if(help()==0)
  342.         {
  343.             clear_screen();
  344.             update_screen(0);
  345.         }
  346.         else error_message("No help available");
  347.         return;
  348.     }
  349.     if (strncmp(cmd, "ve", 2) == 0) {
  350.         msg(VERSION_STRING);
  351.         return;
  352.     }
  353.     if (strcmp(cmd, "sh") == 0) {
  354.         do_shell(NULL);
  355.         return;
  356.     }
  357.     if (*cmd == '!') {
  358.         do_shell(cmdbuf+1);
  359.         return;
  360.     }
  361.     if (strncmp(cmd, "s/", 2) == 0) {
  362.         do_sub(&l_pos, &u_pos, cmdbuf+1);
  363.         return;
  364.     }
  365.     if (strncmp(cmd, "g/", 2) == 0) {
  366.         do_glob(&l_pos, &u_pos, cmdbuf+1);
  367.         return;
  368.     }
  369.     /*
  370.      * If we got a line, but no command, then go to the line.
  371.      */
  372.     if (*cmd == '\0' && l_pos.linep != NULL) {
  373.         *cursor_char = l_pos;
  374.         return;
  375.     }
  376.  
  377.     bad_command();
  378. }
  379.  
  380.  
  381. void do_exit()        /* v1.1 */
  382. {
  383.     if (changed) {
  384.         if (file_name != NULL) {
  385.             if (!write_it(file_name, (LPTR *)NULL, (LPTR *)NULL))
  386.                 return;
  387.         } else {
  388.             error_message(nooutfile);
  389.             return;
  390.         }
  391.     }
  392.     if ((current_file + 1) < number_of_files)
  393.         error_message(morefiles);
  394.     else
  395.         get_out();
  396. }
  397.  
  398. /*
  399.  * get_range - parse a range specifier
  400.  *
  401.  * Ranges are of the form:
  402.  *
  403.  * addr[,addr]
  404.  *
  405.  * where 'addr' is:
  406.  *
  407.  * $  [+- NUM]
  408.  * 'x [+- NUM]  (where x denotes a currently defined mark)
  409.  * .  [+- NUM]
  410.  * NUM
  411.  *
  412.  * The pointer *cp is updated to point to the first character following
  413.  * the range spec. If an initial address is found, but no second, the
  414.  * upper bound is equal to the lower.
  415.  */
  416. static void get_range(cp, lower, upper)
  417. register char   **cp;
  418. LPTR    *lower, *upper;
  419. {
  420.     register LPTR   *l;
  421.     register char   *p;
  422.  
  423.     if ((l = get_line(cp)) == NULL)
  424.         return;
  425.  
  426.     *lower = *l;
  427.  
  428.     for (p = *cp; *p != '\0' && is_space(*p) ;p++)
  429.         ;
  430.  
  431.     *cp = p;
  432.  
  433.     if (*p != ',') {                /* is there another line spec ? */
  434.         *upper = *lower;
  435.         return;
  436.     }
  437.  
  438.     *cp = ++p;
  439.  
  440.     if ((l = get_line(cp)) == NULL) {
  441.         *upper = *lower;
  442.         return;
  443.     }
  444.  
  445.     *upper = *l;
  446. }
  447.  
  448. static LPTR *get_line(cp)
  449. char    **cp;
  450. {
  451.     static  LPTR    pos;
  452.     LPTR    *lp;
  453.     register char   *p, c;
  454.     register int    lnum;
  455.  
  456.     pos.index = 0;          /* shouldn't matter... check back later */
  457.  
  458.     p = *cp;
  459.     /*
  460.      * Determine the basic form, if present.
  461.      */
  462.     switch (c = *p++) {
  463.  
  464.     case '$':
  465.         pos.linep = end_of_file->linep->prev;
  466.         break;
  467.  
  468.     case '.':
  469.         pos.linep = cursor_char->linep;
  470.         break;
  471.  
  472.     case '\'':
  473.         if ((lp = get_mark(*p++)) == NULL) {
  474.             error_message("Unknown mark");
  475.             return (LPTR *) NULL;
  476.         }
  477.         pos = *lp;
  478.         break;
  479.  
  480.     case '0': case '1': case '2': case '3': case '4':
  481.     case '5': case '6': case '7': case '8': case '9':
  482.         for (lnum = c - '0'; is_digit(*p) ;p++)
  483.             lnum = (lnum * 10) + (*p - '0');
  484.  
  485.         pos = *goto_line(lnum);
  486.         break;
  487.  
  488.     default:
  489.         return (LPTR *) NULL;
  490.     }
  491.  
  492.     while (*p != '\0' && is_space(*p))
  493.         p++;
  494.  
  495.     if (*p == '-' || *p == '+') {
  496.         int     neg = (*p++ == '-');
  497.  
  498.         for (lnum = 0; is_digit(*p) ;p++)
  499.             lnum = (lnum * 10) + (*p - '0');
  500.  
  501.         if (neg)
  502.             lnum = -lnum;
  503.  
  504.         pos = *goto_line( cntllines(file_memory, &pos) + lnum );
  505.     }
  506.  
  507.     *cp = p;
  508.     return &pos;
  509. }
  510.  
  511. void bad_command()
  512. {
  513.     error_message("Unrecognized command");
  514. }
  515.  
  516. int do_e_command(arg, force)
  517. char    *arg;
  518. int     force;
  519. {
  520.     int     line = 1;               /* line # to go to in new file */
  521.  
  522.     if (!force && changed) {
  523.         error_message(nowrtmsg);
  524.         if (altfile)
  525.             free(altfile);
  526.         altfile = strsave(arg);
  527.         return (0);
  528.     }
  529.     if (arg != NULL) {
  530.         /*
  531.          * First detect a ":e" on the current file. This is mainly
  532.          * for ":ta" commands where the destination is within the
  533.          * current file.
  534.          */
  535.         if (file_name != NULL && strcmp(arg, file_name) == 0) {
  536.             if (!changed || (changed && !force))
  537.                 return (1);
  538.         }
  539.         if (altfile) {
  540.             if (strcmp (arg, altfile) == 0)
  541.                 line = altline;
  542.             free(altfile);
  543.         }
  544.         altfile = file_name;
  545.         altline = cntllines(file_memory, cursor_char);
  546.         file_name = strsave(arg);
  547.     }
  548.     if (file_name == NULL) {
  549.         error_message("No filename");
  550.         return (0);
  551.     }
  552.  
  553.     /* clear mem and read file */
  554.     freeall();
  555.     file_alloc();
  556.     UNCHANGED;
  557.  
  558.     if (read_file(file_name, file_memory, 0))
  559.         file_message("[New File]");
  560.  
  561.     *top_char = *cursor_char;
  562.     if (line != 1) {
  563.         put_int_into_input_buffer(line);
  564.         put_string_into_input_buffer("G");
  565.     }
  566.     set_pc_mark();
  567.     update_screen(0);
  568.     return (1);
  569. }
  570.  
  571. void goto_command(clr, firstc)
  572. int  clr;
  573. char    firstc;
  574. {
  575.     goto_screen_pos(current_lines-1,0);
  576.     if (clr)termcap_out(termcap_clr_eol); /* clear the bottom line */
  577.     if (firstc)
  578.         putc(firstc,stdout);
  579. }
  580.  
  581. /*
  582.  * msg(s) - displays the string 's' on the status line
  583.  */
  584. void msg(s)
  585. char    *s;
  586. {
  587.     goto_command((1), 0);
  588.     fprintf(stdout,"%s",s);
  589.     fflush(stdout);
  590. }
  591.  
  592. /*VARARGS1*/
  593. void show_message(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)
  594. char    *s;
  595. int     a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16;
  596. {
  597.     char    sbuf[80];
  598.  
  599.     sprintf(sbuf, s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16);
  600.     msg(sbuf);
  601. }
  602.  
  603. /*
  604.  * error_message() - display an error message
  605.  *
  606.  * Rings the bell, if appropriate, and calls message() to do the real work
  607.  */
  608. void error_message(s)
  609. char    *s;
  610. {
  611.     if (PARAMETER_VALUE(PARAMETER_ERRORBELLS))
  612.         beep();
  613.     msg(s);
  614. }
  615.  
  616. void wait_return()
  617. {
  618.     register char   c;
  619.  
  620.     if(local_control_c_pressed())fprintf(stdout,"%s","Interrupt   ");
  621.  
  622.     fprintf(stdout,"Press RETURN to continue");
  623.     do 
  624.     {
  625.         c = get_char_from_input_buffer();
  626.     } 
  627.     while (c != CTRL_J && c != CTRL_M && c != ' ' && c != ':');
  628.  
  629.     if (c == ':') 
  630.     {
  631.         putc('\n',stdout);
  632.         do_command_line(getcmdln(c));
  633.     } 
  634.     else clear_screen();
  635.  
  636.     update_screen(0);
  637. }
  638.