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 / OPS.C < prev    next >
C/C++ Source or Header  |  1993-04-21  |  14KB  |  608 lines

  1. /* 
  2.  * Contains routines that implement the operators in vi. Everything in this
  3.  * file is called only from code in normal.c
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "pvic.h"
  8. #include "locdefs.h"
  9.  
  10. /*
  11.  * do_shift - handle a shift operation
  12.  */
  13. void
  14. do_shift(op, c1, c2, num)
  15. int     op;
  16. char    c1, c2;
  17. int     num;
  18. {
  19.     void    tabinout();
  20.     LPTR    top, bot;
  21.     int     nlines;
  22.     char    opchar;
  23.  
  24.     top = startop;
  25.     bot = *cursor_char;
  26.  
  27.     if (lt(&bot, &top))
  28.         pswap(&top, &bot);
  29.  
  30.     u_save(top.linep->prev, bot.linep->next);
  31.  
  32.     nlines = cntllines(&top, &bot);
  33.     *cursor_char = top;
  34.     tabinout((op == LSHIFT), nlines);
  35.  
  36.     /* construct Redo buff */
  37.     opchar = (op == LSHIFT) ? '<' : '>';
  38.     if (num != 0)
  39.         sprintf(redo_buffer, "%c%d%c%c", opchar, num, c1, c2);
  40.     else
  41.         sprintf(redo_buffer, "%c%c%c", opchar, c1, c2);
  42.  
  43.     /*
  44.      * The cursor position afterward is the prior of the two positions.
  45.      */
  46.     *cursor_char = top;
  47.  
  48.     /*
  49.      * If we were on the last char of a line that got shifted left,
  50.      * then move left one so we aren't beyond the end of the line
  51.      */
  52.     if (gchar(cursor_char) == '\0' && cursor_char->index > 0)
  53.         cursor_char->index--;
  54.  
  55.     update_screen(0);
  56.  
  57.     if (nlines > PARAMETER_VALUE(PARAMETER_REPORT))
  58.         show_message("%d lines %ced", nlines, opchar);
  59. }
  60.  
  61. /*
  62.  * do_delete - handle a delete operation
  63.  */
  64. void
  65. do_delete(c1, c2, num)
  66. char    c1, c2;
  67. int     num;
  68. {
  69.     LPTR    top, bot;
  70.     int     nlines;
  71.     int     botindex;
  72.     register int    n;
  73.  
  74.     /*
  75.      * Do a yank of whatever we're about to delete. If there's too much
  76.      * stuff to fit in the yank buffer, then get a confirmation before
  77.      * doing the delete. This is crude, but simple. And it avoids doing
  78.      * a delete of something we can't put back if we want.
  79.      */
  80.     if (!do_yank()) {
  81.         msg("Yank buffer exceeded, press 'y' to delete anyway");
  82.         if (get_char_from_input_buffer() != 'y') {
  83.             msg("Delete aborted");
  84.             *cursor_char = startop;
  85.             return;
  86.         }
  87.     }
  88.  
  89.     top = startop;
  90.     bot = *cursor_char;
  91.  
  92.     if (lt(&bot, &top))
  93.         pswap(&top, &bot);
  94.  
  95.     u_save(top.linep->prev, bot.linep->next);
  96.     /* Don't leave even the potential for orphan marks */
  97.     clear_mark (top.linep);
  98.  
  99.     nlines = cntllines(&top, &bot);
  100.     *cursor_char = top;
  101.     update_cursor(0);
  102.  
  103.     if (mtype == MLINE) {
  104.         delete_line(nlines, (1));
  105.     } else {
  106.         botindex = -1;
  107.         if (!mincl) {
  108.             botindex = bot.index;   /* where it WAS */
  109.             if (bot.index != 0)
  110.                 dec(&bot);
  111.         }
  112.  
  113.         if (top.linep == bot.linep) {           /* del. within line */
  114.             n = bot.index - top.index + 1;
  115.             while (n--)
  116.                 if (!delete_char((1)))
  117.                     break;
  118.         } else {                                /* del. between lines */
  119.             n = cursor_char->index;
  120.             while (cursor_char->index >= n)
  121.                 if (!delete_char((1)))
  122.                     break;
  123.  
  124.             top = *cursor_char;
  125.             *cursor_char = *next_line(cursor_char);
  126.             delete_line(nlines-2, (1));
  127.             cursor_char->index = 0;
  128.             n = bot.index + 1;
  129.             while (n-- && botindex)
  130.                 if (!delete_char((1)))
  131.                     break;
  132.             *cursor_char = top;
  133.             (void) do_join((0));
  134.             one_right();     /* we got bumped left up above */
  135.         }
  136.     }
  137.  
  138.     /* construct Redo buff */
  139.     if (num != 0)
  140.         sprintf(redo_buffer, "d%d%c%c", num, c1, c2);
  141.     else
  142.         sprintf(redo_buffer, "d%c%c", c1, c2);
  143.  
  144.     if (mtype == MCHAR && nlines == 1)
  145.         update_line();
  146.     else
  147.         update_screen(0);
  148.  
  149.     if (nlines > PARAMETER_VALUE(PARAMETER_REPORT))
  150.         show_message("%d fewer lines", nlines);
  151. }
  152.  
  153. /*
  154.  * do_filter - handle a filter operation
  155.  */
  156.  
  157. #define ITMP    "viXXXXXX"
  158. #define OTMP    "voXXXXXX"
  159.  
  160. static  char    itmp[32];
  161. static  char    otmp[32];
  162.  
  163.  
  164. /*
  165.  * do_filter - filter lines through a command given by the user
  166.  *
  167.  * We use temp files and the system() routine here. This would normally
  168.  * be done using pipes on a UNIX machine, but this is more portable to
  169.  * the machines we usually run on. The system() routine needs to be able
  170.  * to deal with redirection somehow, and should handle things like looking
  171.  * at the PATH env. variable, and adding reasonable extensions to the
  172.  * command name given by the user. All reasonable versions of system()
  173.  * do this.
  174.  */
  175. void
  176. do_filter(c1, c2, num)
  177. char    c1, c2;
  178. int     num;
  179. {
  180.     char    *mktemp();
  181.     static  char    *lastcmd = NULL;/* the last thing we did */
  182.     char    *buff;                  /* cmd buffer from getcmdln() */
  183.     char    cmdln[200];             /* filtering command line */
  184.     LPTR    top, bot;
  185.     int     nlines;
  186.  
  187.     top = startop;
  188.     bot = *cursor_char;
  189.  
  190.     buff = getcmdln('!');
  191.  
  192.     if (buff == NULL)       /* user backed out of the command prompt */
  193.         return;
  194.  
  195.     if (*buff == '!') {             /* use the 'last' command */
  196.         if (lastcmd == NULL) {
  197.             error_message("No previous command");
  198.             return;
  199.         }
  200.         buff = lastcmd;
  201.     }
  202.  
  203.     /*
  204.      * Remember the current command
  205.      */
  206.     if (lastcmd != NULL)
  207.         free(lastcmd);
  208.     lastcmd = strsave(buff);
  209.  
  210.     if (lt(&bot, &top))
  211.         pswap(&top, &bot);
  212.  
  213.     u_save(top.linep->prev, bot.linep->next);
  214.  
  215.     nlines = cntllines(&top, &bot);
  216.     *cursor_char = top;
  217.     update_cursor(0);
  218.  
  219.     /*
  220.      * 1. Form temp file names
  221.      * 2. Write the lines to a temp file
  222.      * 3. Run the filter command on the temp file
  223.      * 4. Read the output of the command into the buffer
  224.      * 5. Delete the original lines to be filtered
  225.      * 6. Remove the temp files
  226.      */
  227.  
  228.     itmp[0] = otmp[0] = '\0';
  229.  
  230.     strcat(itmp, ITMP);
  231.     strcat(otmp, OTMP);
  232.  
  233.     if (mktemp(itmp) == NULL || mktemp(otmp) == NULL) {
  234.         error_message("Can't get temp file names");
  235.         return;
  236.     }
  237.  
  238.     if (!write_it(itmp, &top, &bot)) {
  239.         error_message("Can't create input temp file");
  240.         return;
  241.     }
  242.  
  243.     sprintf(cmdln, "%s <%s >%s", buff, itmp, otmp);
  244.  
  245.         local_deinit_terminal_io();
  246.     if (system(cmdln) != 0) {
  247.                 local_init_terminal_io();
  248.         error_message("Filter command failed");
  249.         unlink(ITMP);
  250.         return;
  251.     }
  252.         else local_init_terminal_io();
  253.  
  254.     if (read_file(otmp, &bot, (1))) {
  255.         error_message("Can't read filter output");
  256.         return;
  257.     }
  258.  
  259.     delete_line(nlines, (1));
  260.  
  261.     unlink(itmp);
  262.     unlink(otmp);
  263.  
  264.     /* construct Redo buff */
  265.     if (num != 0)
  266.         sprintf(redo_buffer, "d%d%c%c", num, c1, c2);
  267.     else
  268.         sprintf(redo_buffer, "d%c%c", c1, c2);
  269.  
  270.     update_screen(0);
  271.  
  272.     if (nlines > PARAMETER_VALUE(PARAMETER_REPORT))
  273.         show_message("%d lines filtered", nlines);
  274. }
  275.  
  276.  
  277.  
  278.  
  279. /*
  280.  * do_change - handle a change operation
  281.  */
  282. void
  283. do_change(c1, c2, num)
  284. char    c1, c2;
  285. int     num;
  286. {
  287.     char    sbuf[16];
  288.     int     doappend;       /* true if we should do append, not insert */
  289.     int     at_eof;         /* changing through the end of file */
  290.     LPTR    top, bot;
  291.  
  292.     top = startop;
  293.     bot = *cursor_char;
  294.  
  295.     if (lt(&bot, &top))
  296.         pswap(&top, &bot);
  297.  
  298.     doappend = end_of_line(&bot);
  299.     at_eof = (bot.linep->next == end_of_file->linep);
  300.  
  301.     do_delete(c1, c2, num);
  302.  
  303.     if (mtype == MLINE) {
  304.         /*
  305.          * If we made a change through the last line of the file,
  306.          * then the cursor got backed up, and we need to open a
  307.          * new line forward, otherwise we go backward.
  308.          */
  309.         if (at_eof)
  310.             open_command(SEARCH_FORWARD, (0));
  311.         else
  312.             open_command(SEARCH_BACKWARD, (0));
  313.     } else {
  314.         if (doappend && !line_empty())
  315.             inc(cursor_char);
  316.     }
  317.  
  318.     if (num)
  319.         sprintf(sbuf, "c%d%c%c", num, c1, c2);
  320.     else
  321.         sprintf(sbuf, "c%c%c", c1, c2);
  322.  
  323.     do_start_insert(sbuf, mtype == MLINE);
  324. }
  325.  
  326. #ifndef YBSIZE
  327. #define YBSIZE  4096
  328. #endif
  329.  
  330. static  char    ybuf[YBSIZE];
  331. static  int     ybtype = MBAD;
  332.  
  333. int
  334. do_yank()
  335. {
  336.     LPTR    top, bot;
  337.     char    *yptr = ybuf;
  338.     char    *ybend = &ybuf[YBSIZE-1];
  339.     int     nlines;
  340.  
  341.     top = startop;
  342.     bot = *cursor_char;
  343.  
  344.     if (lt(&bot, &top))
  345.         pswap(&top, &bot);
  346.  
  347.     nlines = cntllines(&top, &bot);
  348.  
  349.     ybtype = mtype;                 /* set the yank buffer type */
  350.  
  351.     if (mtype == MLINE) {
  352.         top.index = 0;
  353.         bot.index = strlen(bot.linep->s);
  354.         /*
  355.          * The following statement checks for the special case of
  356.          * yanking a blank line at the beginning of the file. If
  357.          * not handled right, we yank an extra char (a newline).
  358.          */
  359.         if (dec(&bot) == -1) {
  360.             ybuf[0] = '\0';
  361.             if (operator == YANK)
  362.                 *cursor_char = startop;
  363.             return (1);
  364.         }
  365.     } else {
  366.         if (!mincl) {
  367.             if (bot.index)
  368.                 bot.index--;
  369.             else            /* already first column */
  370.                 bot = *( previous_char (&bot));
  371.         }
  372.     }
  373.  
  374.     for (; ltoreq(&top, &bot) ;inc(&top)) {
  375.         *yptr = (gchar(&top) != '\0') ? gchar(&top) : '\n';
  376.         if (++yptr >= ybend) {
  377.             msg("Yank too big for buffer");
  378.             ybtype = MBAD;
  379.             return (0);
  380.         }
  381.     }
  382.  
  383.     *yptr = '\0';
  384.  
  385.     if (operator == YANK) { /* restore cursor_char if really doing yank */
  386.         *cursor_char = startop;
  387.  
  388.         if (nlines > PARAMETER_VALUE(PARAMETER_REPORT))
  389.             show_message("%d lines yanked", nlines);
  390.     }
  391.  
  392.     return (1);
  393. }
  394.  
  395. /*
  396.  * do_put(dir)
  397.  *
  398.  * Put the yank buffer at the current location, using the direction given
  399.  * by 'dir'.
  400.  */
  401. void
  402. do_put(dir)
  403. int     dir;
  404. {
  405.     void    inslines();
  406.  
  407.     if (ybtype == MBAD) {
  408.         beep();
  409.         return;
  410.     }
  411.     
  412.     u_save_line();
  413.  
  414.     if (ybtype == MLINE)
  415.         inslines(cursor_char->linep, dir, ybuf);
  416.     else {
  417.         /*
  418.          * If we did a character-oriented yank, and the buffer
  419.          * contains multiple lines, the situation is more complex.
  420.          * For the moment, we punt, and pretend the user did a
  421.          * line-oriented yank. This doesn't actually happen that
  422.          * often.
  423.          */
  424.         if (get_pointer_to_chr_in_string(ybuf, '\n') != NULL)
  425.             inslines(cursor_char->linep, dir, ybuf);
  426.         else {
  427.             char    *s;
  428.             int     len;
  429.  
  430.             len = strlen(cursor_char->linep->s) + strlen(ybuf) + 1;
  431.             s = alloc((unsigned) len);
  432.             if (!s)  return;
  433.             strcpy(s, cursor_char->linep->s);
  434.             if (dir == SEARCH_FORWARD)
  435.                 cursor_char->index++;
  436.             strcpy(s + cursor_char->index, ybuf);
  437.             strcat(s, &cursor_char->linep->s[cursor_char->index]);
  438.             free(cursor_char->linep->s);
  439.             cursor_char->linep->s = s;
  440.             cursor_char->linep->size = len;
  441.             update_line();
  442.         }
  443.     }
  444.  
  445.     CHANGED;
  446. }
  447.  
  448. int
  449. do_join(join_cmd)
  450. int     join_cmd;               /* handling a real "join" command? */
  451. {
  452.     int     scol;           /* save cursor column */
  453.     int     size;           /* size of the joined line */
  454.  
  455.     if (next_line(cursor_char) == NULL)         /* on last line */
  456.         return (0);
  457.  
  458.     if (!can_increase(size = strlen(cursor_char->linep->next->s)))
  459.         return (0);
  460.  
  461.     while (one_right())                      /* to end of line */
  462.         ;
  463.  
  464.     strcat(cursor_char->linep->s, cursor_char->linep->next->s);
  465.  
  466.     /*
  467.      * Delete the following line. To do this we move the cursor
  468.      * there briefly, and then move it back. Don't back up if the
  469.      * delete made us the last line.
  470.      */
  471.     cursor_char->linep = cursor_char->linep->next;
  472.     scol = cursor_char->index;
  473.  
  474.     if (next_line(cursor_char) != NULL) {
  475.         delete_line(1, (1));
  476.         cursor_char->linep = cursor_char->linep->prev;
  477.     } else
  478.         delete_line(1, (1));
  479.  
  480.     cursor_char->index = scol;
  481.  
  482.     if (join_cmd)
  483.         one_right();     /* go to first char. of joined line */
  484.  
  485.     if (join_cmd && size != 0) {
  486.         /*
  487.          * Delete leading white space on the joined line
  488.          * and insert a single space.
  489.          */
  490.         while (gchar(cursor_char) == ' ' || gchar(cursor_char) == CTRL_I)
  491.             delete_char((1));
  492.         inschar(' ');
  493.     }
  494.  
  495.     return (1);
  496. }
  497.  
  498. void
  499. do_start_insert(initstr, startln)
  500. char    *initstr;
  501. int     startln;        /* if set, insert point really at start of line */
  502. {
  503.     register char   *p, c;
  504.  
  505.     *start_insert = *cursor_char;
  506.     if (startln)
  507.         start_insert->index = 0;
  508.     insert_n = 0;
  509.     insert_pointer = insert_buffer;
  510.     for (p=initstr; (c=(*p++))!='\0'; )
  511.         *insert_pointer++ = c;
  512.  
  513.     if (*initstr == 'R')
  514.         current_status = STATUS_REPLACE;
  515.     else
  516.         current_status = STATUS_INSERT;
  517.  
  518.     if (PARAMETER_VALUE(PARAMETER_SHOWMODE))
  519.         msg((current_status == STATUS_INSERT) ? "Insert mode" : "Replace mode");
  520. }
  521. /*
  522.  * tabinout(inout,num)
  523.  *
  524.  * If inout==0, add a tab to the begining of the next num lines.
  525.  * If inout==1, delete a tab from the beginning of the next num lines.
  526.  */
  527. static void
  528. tabinout(inout, num)
  529. int     inout;
  530. int     num;
  531. {
  532.     int     ntodo = num;
  533.     LPTR    *p;
  534.  
  535.     begin_line((0));
  536.     while (ntodo-- > 0) {
  537.         begin_line((0));
  538.         if (inout == 0)
  539.             inschar(CTRL_I);
  540.         else {
  541.             if (gchar(cursor_char) == CTRL_I)
  542.                 delete_char((1));
  543.         }
  544.         if ( ntodo > 0 ) {
  545.             if ((p = next_line(cursor_char)) != NULL)
  546.                 *cursor_char = *p;
  547.             else
  548.                 break;
  549.         }
  550.     }
  551. }
  552.  
  553. /*
  554.  * inslines(lp, dir, buf)
  555.  *
  556.  * Inserts lines in the file from the given buffer. Lines are inserted
  557.  * before or after "lp" according to the given direction flag. Newlines
  558.  * in the buffer result in multiple lines being inserted. The cursor
  559.  * is left on the first of the inserted lines.
  560.  */
  561. static void
  562. inslines(lp, dir, buf)
  563. LINE    *lp;
  564. int     dir;
  565. char    *buf;
  566. {
  567.     register char   *cp = buf;
  568.     register int    len;
  569.     char    *ep;
  570.     LINE    *l, *nc = NULL;
  571.  
  572.     if (dir == SEARCH_BACKWARD)
  573.         lp = lp->prev;
  574.  
  575.     do {
  576.         if ((ep = get_pointer_to_chr_in_string(cp, '\n')) == NULL)
  577.             len = strlen(cp);
  578.         else
  579.             len = ep - cp;
  580.  
  581.         l = newline(len);
  582.         if (len != 0)
  583.             strncpy(l->s, cp, len);
  584.         l->s[len] = '\0';
  585.  
  586.         l->next = lp->next;
  587.         l->prev = lp;
  588.         lp->next->prev = l;
  589.         lp->next = l;
  590.  
  591.         if (nc == NULL)
  592.             nc = l;
  593.  
  594.         lp = lp->next;
  595.  
  596.         cp = ep + 1;
  597.     } while (ep != NULL);
  598.  
  599.     if (dir == SEARCH_BACKWARD)     /* fix the top line in case we were there */
  600.         file_memory->linep = top_of_file->linep->next;
  601.  
  602.     renum();
  603.  
  604.     update_screen(0);
  605.     cursor_char->linep = nc;
  606.     cursor_char->index = 0;
  607. }
  608.