home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume22 / sc6.8 / part05 / vi.c < prev    next >
C/C++ Source or Header  |  1990-09-30  |  11KB  |  615 lines

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