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