home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Product / Product.zip / sc621_3.zip / src / vi.c < prev    next >
C/C++ Source or Header  |  1992-06-01  |  13KB  |  737 lines

  1. /*    SC    A Spreadsheet Calculator
  2.  *
  3.  *    One line vi emulation
  4.  *    $Revision: 6.21 $
  5.  */
  6.  
  7. #include <sys/types.h>
  8. #ifdef BSD42
  9. #include <strings.h>
  10. #else
  11. #ifndef SYSIII
  12. #include <string.h>
  13. #endif
  14. #endif
  15.  
  16. #include <signal.h>
  17. #include <curses.h>
  18.  
  19. extern    char    *strchr();
  20.  
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include "sc.h"
  24.  
  25. #define istext(a) (isalnum(a) || ((a) == '_'))
  26.  
  27. static    void append_line();
  28. static    void back_hist();
  29. static    int  back_line();
  30. static    int  back_word();
  31. static    void back_space();
  32. static    void change_cmd();
  33. static    void col_0();
  34. static    void cr_line();
  35. static    void delete_cmd();
  36. static    void del_chars();
  37. static    void del_in_line();
  38. static    void del_to_end();
  39. static    void dotcmd();
  40. static    int  find_char();
  41. static    void for_hist();
  42. static    int  for_line();
  43. static    int  for_word();
  44. static    void ins_in_line();
  45. static    void last_col();
  46. static    void rep_char();
  47. static    void replace_in_line();
  48. static    void replace_mode();
  49. static    void restore_it();
  50. static    void savedot();
  51. static    void save_hist();
  52. static    void search_again();
  53. static    void search_hist();
  54. static    void search_mode();
  55. static    void stop_edit();
  56. static    int  to_char();
  57. static    void u_save();
  58.  
  59. extern int showrange;
  60. extern char mode_ind;        /* Mode indicator */
  61.  
  62. /* values for mode below */
  63.  
  64. #define INSERT_MODE    0    /* Insert mode */
  65. #define EDIT_MODE       1    /* Edit mode */
  66. #define REP_MODE        2    /* Replace mode */
  67. #define SEARCH_MODE    3    /* Get arguments for '/' command */
  68.  
  69. #define    DOTLEN        200
  70.  
  71. static int mode = INSERT_MODE;
  72. struct    hist {
  73.     unsigned    int    len;
  74.     char    *histline;
  75. } history[HISTLEN];
  76.  
  77. static int histp = -1;
  78. static int lasthist = -1;
  79. static int endhist = -1;
  80. static char *last_search = NULL;
  81. static char *undo_line = NULL;
  82. static int undo_lim;
  83. static char dotb[DOTLEN];
  84. static int doti = 0;
  85. static int do_dot = 0;
  86.  
  87. void
  88. write_line(c)
  89. int c;
  90. {
  91.     if (mode == EDIT_MODE) {
  92.     switch(c) {
  93.     case (ctl('h')):    linelim = back_line();        break;
  94.     case (ctl('m')):  cr_line();            break;
  95.     case ESC:    stop_edit();            break;
  96.     case '+':    for_hist();            break;
  97.     case '-':    back_hist();            break;
  98.     case '$':    last_col();            break;
  99.     case '.':    dotcmd();            break;
  100.     case '/':    search_mode();            break;
  101.     case '0':    col_0();            break;
  102.     case 'D':    u_save(c);del_to_end();        break;
  103.     case 'I':    u_save(c);col_0();insert_mode();break;
  104.     case 'R':    replace_mode();            break;
  105.     case 'X':    u_save(c); back_space();    break;
  106.     case 'a':    u_save(c); append_line();    break;
  107.     case 'A':    u_save(c);last_col();append_line();    break;
  108.     case 'b':    linelim = back_word();        break;
  109.     case 'c':    u_save(c); change_cmd();    break;
  110.     case 'd':    u_save(c); delete_cmd();    break;
  111.     case 'f':    linelim = find_char();        break;
  112.     case 'h':    linelim = back_line();        break;
  113.     case 'i':    u_save(c); insert_mode();    break;
  114.     case 'j':    for_hist();            break;
  115.     case 'k':    back_hist();            break;
  116.     case ' ':
  117.     case 'l':    linelim = for_line(0);        break;
  118.     case 'n':    search_again();            break;
  119.     case 'q':    stop_edit();            break;
  120.     case 'r':    u_save(c); rep_char();        break;
  121.     case 't':    linelim = to_char();        break;
  122.     case 'u':    restore_it();            break;
  123.     case 'w':    linelim = for_word(0);        break;
  124.     case 'x':    u_save(c); del_in_line();    break;
  125.     default:    break;
  126.     }
  127.     } else if (mode == INSERT_MODE) { 
  128.     savedot(c);
  129.     switch(c) {
  130.     case (ctl('h')):    back_space();            break;
  131.     case (ctl('m')):  cr_line();            break;
  132.     case ESC:    edit_mode();            break;
  133.     default:    ins_in_line(c);            break;
  134.     }
  135.     } else if (mode == SEARCH_MODE) {
  136.     switch(c) {
  137.     case (ctl('h')):    back_space();            break;
  138.     case (ctl('m')):  search_hist();            break;
  139.     case ESC:    edit_mode();            break;
  140.     default:    ins_in_line(c);            break;
  141.     }
  142.    } else if (mode == REP_MODE) {
  143.     savedot(c);
  144.     switch(c) {
  145.     case (ctl('h')):    back_space();            break;
  146.     case (ctl('m')):  cr_line();            break;
  147.     case ESC:    edit_mode();            break;
  148.     default:    replace_in_line(c);        break;
  149.     }
  150.     }
  151. }
  152.  
  153. void
  154. edit_mode()
  155. {
  156.     mode = EDIT_MODE;
  157.     mode_ind = 'e';
  158.     histp = -1;
  159.     if (linelim < 0)    /* -1 says stop editing, ...so we still aren't */
  160.     return;
  161.     if (line[linelim] == '\0')
  162.     linelim = back_line();
  163. }
  164.  
  165. void
  166. insert_mode()
  167. {
  168.     mode_ind = 'i';
  169.     mode = INSERT_MODE;
  170. }
  171.  
  172. static    void
  173. search_mode()
  174. {
  175.     line[0] = '/';
  176.     line[1] = '\0';
  177.     linelim = 1;
  178.     histp = -1;
  179.     mode_ind = '/';
  180.     mode = SEARCH_MODE;
  181. }
  182.  
  183. static    void
  184. replace_mode()
  185. {
  186.     mode_ind = 'R';
  187.     mode = REP_MODE;
  188. }
  189.  
  190. /* dot command functions.  Saves info so we can redo on a '.' command */
  191.  
  192. static    void
  193. savedot(c)
  194. int c;
  195. {
  196.     if (do_dot || (c == '\n'))
  197.     return;
  198.  
  199.     if (doti < DOTLEN-1)
  200.     {
  201.     dotb[doti++] = c;
  202.     dotb[doti] = '\0';
  203.     }
  204. }
  205.  
  206. static int dotcalled = 0;
  207.  
  208. static    void
  209. dotcmd()
  210. {
  211.     int c;
  212.  
  213.     if (dotcalled)    /* stop recursive calling of dotcmd() */
  214.     return;
  215.     do_dot = 1;
  216.     doti = 0;
  217.     while(dotb[doti] != '\0') {
  218.     c = dotb[doti++];
  219.     dotcalled = 1;
  220.     write_line(c);
  221.     }
  222.     do_dot = 0;
  223.     doti = 0;
  224.     dotcalled = 0;
  225. }
  226.  
  227. int
  228. vigetch()
  229. {
  230.     int c;
  231.  
  232.     if(do_dot) {
  233.     if (dotb[doti] != '\0') {
  234.         return(dotb[doti++]);
  235.     } else {
  236.         do_dot = 0;
  237.         doti = 0;
  238.         return(nmgetch());
  239.     }
  240.     }
  241.     c = nmgetch();
  242.     savedot(c);
  243.     return(c);
  244. }
  245.  
  246. /* saves the current line for possible use by an undo cmd */
  247. static    void
  248. u_save(c)
  249. int c;
  250. {   static    unsigned    undolen = 0;
  251.  
  252.     if (strlen(line)+1 > undolen)
  253.     {    undolen = strlen(line)+40;
  254.  
  255.     undo_line = scxrealloc(undo_line, undolen);
  256.     }
  257.     (void) strcpy(undo_line, line);
  258.  
  259.     undo_lim = linelim;
  260.  
  261.     /* reset dot command if not processing it. */
  262.  
  263.     if (!do_dot) {
  264.         doti = 0;
  265.     savedot(c);
  266.     }
  267. }
  268.  
  269. /* Restores the current line saved by u_save() */
  270. static    void
  271. restore_it()
  272. {
  273.     static    char *tempc = NULL;
  274.     static    unsigned templen = 0;
  275.     int        tempi;
  276.  
  277.     if ((undo_line == NULL) || (*undo_line == '\0')) 
  278.     return;
  279.  
  280.     if (strlen(line)+1 > templen)
  281.     {    templen = strlen(line)+40;
  282.     tempc = scxrealloc(tempc, templen);
  283.     }
  284.  
  285.     strcpy(tempc, line);
  286.     tempi = linelim;
  287.     (void) strcpy(line, undo_line);
  288.     linelim = undo_lim;
  289.     strcpy(undo_line, tempc);
  290.     undo_lim = tempi;
  291. }
  292.  
  293. /* This command stops the editing process. */
  294. static    void
  295. stop_edit()
  296. {
  297.     showrange = 0;
  298.     linelim = -1;
  299.     (void) move(1, 0);
  300.     (void) clrtoeol();
  301. }
  302.  
  303. /*
  304.  * Motion commands.  Forward motion commands take an argument
  305.  * which, when set, cause the forward motion to continue onto
  306.  * the null at the end of the line instead of stopping at the
  307.  * the last character of the line.
  308.  */
  309. static    int
  310. for_line(stop_null)
  311. int stop_null;
  312. {
  313.     if (linelim >= 0 && line[linelim] != '\0' && 
  314.                     (line[linelim+1] != '\0' || stop_null))
  315.     return(linelim+1);
  316.     else
  317.     return(linelim);
  318. }
  319.  
  320. static    int
  321. for_word(stop_null)
  322. int stop_null;
  323. {
  324.     register int c;
  325.     register int cpos;
  326.  
  327.     cpos = linelim;
  328.  
  329.     if (line[cpos] == ' ') {
  330.     while (line[cpos] == ' ')
  331.         cpos++;
  332.     if (cpos > 0 && line[cpos] == '\0')
  333.         --cpos;
  334.     return(cpos);
  335.     }
  336.  
  337.     if (istext(line[cpos])) {
  338.         while ((c = line[cpos]) && istext(c)) 
  339.         cpos++;
  340.     } else {
  341.     while ((c = line[cpos]) && !istext(c) && c != ' ')
  342.         cpos++;
  343.     }
  344.  
  345.     while (line[cpos] == ' ')
  346.         cpos++;
  347.  
  348.     if (cpos > 0 && line[cpos] == '\0' && !stop_null) 
  349.         --cpos;
  350.  
  351.     return(cpos);
  352. }
  353.  
  354. static    int
  355. back_line()
  356. {
  357.     if (linelim)
  358.         return(linelim-1);
  359.     else
  360.     return(0);
  361. }
  362.  
  363. static    int
  364. back_word()
  365. {
  366.     register int c;
  367.     register int cpos;
  368.  
  369.     cpos = linelim;
  370.  
  371.     if (line[cpos] == ' ') {
  372.     /* Skip white space */
  373.         while (cpos > 0 && line[cpos] == ' ')
  374.         --cpos;
  375.     } else if (cpos > 0 && (line[cpos-1] == ' ' 
  376.              ||  istext(line[cpos]) && !istext(line[cpos-1])
  377.              || !istext(line[cpos]) &&  istext(line[cpos-1]))) {
  378.     /* Started on the first char of a word - back up to prev. word */
  379.     --cpos;
  380.         while (cpos > 0 && line[cpos] == ' ')
  381.         --cpos;
  382.     }
  383.  
  384.     /* Skip across the word - goes 1 too far */
  385.     if (istext(line[cpos])) {
  386.         while (cpos > 0 && (c = line[cpos]) && istext(c)) 
  387.         --cpos;
  388.     } else {
  389.     while (cpos > 0 && (c = line[cpos]) && !istext(c) && c != ' ')
  390.         --cpos;
  391.     }
  392.  
  393.     /* We are done - fix up the one too far */
  394.     if (cpos > 0 && line[cpos] && line[cpos+1]) 
  395.     cpos++;
  396.  
  397.     return(cpos);
  398. }
  399.  
  400. /* Text manipulation commands */
  401.  
  402. static    void
  403. del_in_line()
  404. {
  405.     register int len, i;
  406.  
  407.     if (linelim >= 0) {
  408.     len = strlen(line);
  409.     if (linelim == len && linelim > 0)
  410.         linelim--;
  411.     for (i = linelim; i < len; i++)
  412.         line[i] = line[i+1];
  413.     }
  414.     if (linelim > 0 && line[linelim] == '\0')
  415.     --linelim;
  416. }
  417.  
  418. static    void
  419. ins_in_line(c)
  420. int c;
  421. {
  422.     register int i, len;
  423.  
  424.     if (linelim < 0)
  425.     {    *line = '\0';
  426.     linelim = 0;
  427.     }
  428.     len = strlen(line);
  429.     for (i = len; i >= linelim; --i)
  430.     line[i+1] = line[i];
  431.     line[linelim++] = c;
  432.     line[len+1] = '\0';
  433. }
  434.  
  435. void
  436. ins_string(s)
  437. char *s;
  438. {
  439.     while (*s)
  440.     ins_in_line(*s++);
  441. }
  442.  
  443. static    void
  444. append_line()
  445. {
  446.     register int i;
  447.  
  448.     i = linelim;
  449.     if (i >= 0 && line[i])
  450.     linelim++;
  451.     insert_mode();
  452. }
  453.  
  454. static    void
  455. rep_char()
  456. {
  457.     int c;
  458.  
  459.     if (linelim < 0)
  460.     {    linelim = 0;
  461.     *line = '\0';
  462.     }
  463.     c = vigetch();
  464.     if (line[linelim] != '\0') {
  465.         line[linelim] = c;
  466.     } else {
  467.     line[linelim] = c;
  468.     line[linelim+1] = '\0';
  469.     }
  470. }
  471.  
  472. static    void
  473. replace_in_line(c)
  474. int    c;
  475. {
  476.     register int len;
  477.  
  478.     if (linelim < 0)
  479.     {    linelim = 0;
  480.     *line = '\0';
  481.     }
  482.     len = strlen(line);
  483.     line[linelim++] = c;
  484.     if (linelim > len)
  485.     line[linelim] = '\0';
  486. }
  487.  
  488. static    void
  489. back_space()
  490. {
  491.     if (linelim == 0)
  492.     return;
  493.  
  494.     if (line[linelim] == '\0') {
  495.     linelim = back_line();
  496.     del_in_line();
  497.     linelim = strlen(line);
  498.     } else {
  499.     linelim = back_line();
  500.     del_in_line();
  501.     }
  502. }
  503.  
  504. int
  505. get_motion()
  506. {
  507.     int c;
  508.  
  509.     c = vigetch();
  510.     switch (c) {
  511.     case 'b':    return(back_word());
  512.     case 'f':    return(find_char()+1);
  513.     case 'h':    return(back_line());
  514.     case 'l':    return(for_line(1));
  515.     case 't':    return(to_char()+1);
  516.     case 'w':    return(for_word(1));
  517.     default:    return(linelim);
  518.     }
  519. }
  520.  
  521. static    void
  522. delete_cmd()
  523. {
  524.     int cpos;
  525.  
  526.     cpos = get_motion();
  527.     del_chars(cpos, linelim);
  528. }
  529.  
  530. static    void
  531. change_cmd()
  532. {
  533.     delete_cmd();
  534.     insert_mode();
  535. }
  536.  
  537. static    void
  538. del_chars(first, last)
  539. register int first, last;
  540. {
  541.     int temp;
  542.  
  543.     if (first == last)
  544.     return;
  545.  
  546.     if (last < first) {
  547.     temp = last; last = first; first = temp;
  548.     }
  549.  
  550.     linelim = first;
  551.     while(first < last) {
  552.     del_in_line();
  553.     --last;
  554.     }
  555. }
  556.  
  557. static    void
  558. del_to_end()
  559. {
  560.     if (linelim < 0)
  561.     return;
  562.     line[linelim] = '\0';
  563.     linelim = back_line();
  564. }
  565.  
  566. static    void
  567. cr_line()
  568. {
  569.     insert_mode();
  570.     if (linelim != -1) {
  571.     showrange = 0;
  572.     save_hist();
  573.     linelim = 0;
  574.     (void) yyparse ();
  575.     linelim = -1;
  576.     }
  577.     else    /* '\n' alone will put you into insert mode */
  578.     {    *line = '\0';
  579.     linelim = 0;
  580.     }
  581. }
  582.  
  583. /* History functions */
  584.  
  585. static    void
  586. save_hist()
  587. {
  588.     if (lasthist < 0)
  589.     {    lasthist = 0;
  590.     }
  591.     else
  592.     lasthist = (lasthist + 1) % HISTLEN;
  593.  
  594.     if (lasthist > endhist)
  595.     endhist = lasthist;
  596.  
  597.     if (history[lasthist].len < strlen(line)+1)
  598.     {    history[lasthist].len = strlen(line)+40;
  599.     history[lasthist].histline = scxrealloc(history[lasthist].histline,
  600.                           history[lasthist].len);
  601.     }
  602.     (void) strcpy(history[lasthist].histline, line);
  603. }
  604.  
  605. static    void
  606. back_hist()
  607. {
  608.     if (histp == -1)
  609.     histp = lasthist;
  610.     else
  611.     if (histp == 0)
  612.     {    if (endhist != lasthist)
  613.         histp = endhist;
  614.     }
  615.     else
  616.     if (histp != ((lasthist + 1) % (endhist + 1)))
  617.     histp--;
  618.  
  619.     if (lasthist < 0)
  620.     line[linelim = 0] = '\0';
  621.     else {
  622.         (void) strcpy(line, history[histp].histline);
  623.     linelim = 0;
  624.     }
  625. }
  626.  
  627. static    void
  628. search_hist()
  629. {
  630.     static    unsigned lastsrchlen = 0;
  631.  
  632.     if(linelim < 1) {
  633.     linelim = 0;
  634.     edit_mode();
  635.     return;
  636.     }
  637.  
  638.     if (strlen(line)+1 > lastsrchlen)
  639.     {    lastsrchlen = strlen(line)+40;
  640.     last_search = scxrealloc(last_search, lastsrchlen);
  641.     }
  642.     (void)strcpy(last_search, line+1);
  643.     search_again();
  644.     mode = EDIT_MODE;
  645. }
  646.  
  647. static    void
  648. search_again()
  649. {
  650.     int found_it;
  651.     int do_next;
  652.     int prev_histp;
  653.     char *look_here;
  654.  
  655.     prev_histp = histp;
  656.     if ((last_search == NULL) || (*last_search == '\0'))
  657.     return;
  658.  
  659.     do {
  660.     back_hist();
  661.     if (prev_histp == histp)
  662.         break;
  663.     prev_histp = histp;
  664.     look_here = line;
  665.     found_it = do_next = 0;
  666.     while ((look_here = (char *)strchr(look_here, *last_search)) != NULL &&
  667.                         !found_it && !do_next) {
  668.  
  669.         if (strncmp(look_here, last_search, strlen(last_search)) == 0)
  670.         found_it++;
  671.         else if (look_here < line + strlen(line) - 1)
  672.             look_here++;
  673.         else
  674.         do_next++;
  675.     }
  676.     } while (!found_it);
  677. }
  678.  
  679. static    void
  680. for_hist()
  681. {
  682.     if (histp == -1)
  683.     histp = lasthist;
  684.     else
  685.     if (histp != lasthist)
  686.     histp = (histp + 1) % (endhist + 1);
  687.  
  688.     if (lasthist < 0)
  689.     line[linelim = 0] = '\0';
  690.     else {
  691.     (void) strcpy(line, history[histp].histline);
  692.     linelim = 0;
  693.     }
  694. }
  695.  
  696. static    void
  697. col_0()
  698. {
  699.     linelim = 0;
  700. }
  701.  
  702. static    void
  703. last_col()
  704. {
  705.     linelim = strlen(line);
  706.     if (linelim > 0)
  707.     --linelim;
  708. }
  709.  
  710. static    int
  711. find_char()
  712. {
  713.     register int c;
  714.     register int i;
  715.  
  716.  
  717.     c = vigetch();
  718.     i = linelim;
  719.     while(line[i] && line[i] != c)
  720.     i++;
  721.     if (!line[i])
  722.     i = linelim;
  723.     return(i);
  724. }
  725.  
  726. static    int
  727. to_char()
  728. {
  729.     register int i;
  730.  
  731.     i = find_char();
  732.     if (i > 0 && i != linelim)
  733.     --i;
  734.  
  735.     return(i);
  736. }
  737.