home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1780 / edit.c next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  8.1 KB  |  445 lines

  1. /******************************************************************************
  2. *                                                                             *
  3. *                                    edit.c                                   *
  4. *                                                                             *
  5. ******************************************************************************/
  6.  
  7. /*--------------------------  INITIAL CODING DATE -----------------------------
  8. Tue Sep 12 09:09:54 EDT 1989 by George M. Bogatko
  9.  
  10. --------------------------------  HEADER FILES  -----------------------------*/
  11. #include <stdio.h>
  12. #include <signal.h>
  13. #include <sys/types.h>
  14. #include <sys/termio.h>
  15. #include <setjmp.h>
  16. #include <ctype.h>
  17.  
  18. /*------------------  TYPEDEF'S, DEFINES, STRUCTURE DEF'S  ------------------*/
  19. #define ESC 27
  20. #define BELL write(1, &bell, 1)
  21. #define CURBACK write(1, &curback, 1)
  22. #define SPACE write(1, &space, 1)
  23. #define PROMPT write(1, prompt, strlen(prompt))
  24.  
  25. #ifdef NOSIGSET
  26. #define sigset signal
  27. #endif
  28.  
  29. /*----------------  IMPORTED GLOBAL VARIABLE/FUNCTION DEF'S  ----------------*/
  30.  
  31. /*----------------  EXPORTED GLOBAL VARIABLE/FUNCTION DEF'S  ----------------*/
  32. extern int edit();
  33.  
  34. /*----------------  INTERNAL GLOBAL VARIABLE/FUNCTION DEF'S  ----------------*/
  35. #ident "%W% %G% - George M. Bogatko -"
  36.  
  37. /* static */ extern void sig_handle();
  38. static jmp_buf jumpbuf;
  39. static int lastlen; /* length of the last edited buffer, for blanking out */
  40.  
  41. #ifdef NOSIGSET
  42. static int (*oldintsig)();
  43. static int (*oldquitsig)();
  44. #else
  45. static void (*oldintsig)();
  46. static void (*oldquitsig)();
  47. #endif
  48.  
  49. static char *spaces=
  50. "                                                                           ";
  51. static char *backspaces="\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
  52.  
  53.  
  54. /*-----------------------------------------------------------------------------
  55.  
  56. SYNOPSIS:
  57.     int edit(char *buf, char *prompt)
  58.  
  59. DESCRIPTION:
  60.  
  61.     EDIT is the workhorse of the 'edline' command line editor.  It
  62.     takes a buffer of characters, and applies the following editing
  63.     commands to it:
  64.  
  65.     ACCEPT LINE              <return>
  66.     APPEND                 a
  67.     DELETE A CHAR               x
  68.     REPLACE A CHAR          r
  69.     END INSERT/APPEND MODE         ESC
  70.     ERASE LINE AND START AGAIN     BREAK(break key) or QUIT(ctrl-\)
  71.     INSERT                   i
  72.     MOVE BACKWARD A WORD         b
  73.     MOVE DOWN A LINE         j
  74.     MOVE FORWARD A WORD         w
  75.     MOVE LEFT A CHAR         h
  76.     MOVE RIGHT A CHAR         l
  77.     MOVE TO BEGINNING OF LINE    0
  78.     MOVE TO END OF LINE         $
  79.     MOVE UP A LINE             k
  80.  
  81.     The function does NOT rely on any TERM setting, but does everything
  82.     with writes and backspaces.
  83.  
  84.     ioctl is used to set the terminal in RAW mode.  SIGINT and SIGQUIT are
  85.     trapped to restore the previous settings.
  86.  
  87.     The function returns the last character hit, or 255 if SIGINT or
  88.     SIGQUIT are caught.
  89.  
  90.  
  91. CAVEATS:
  92.     Certain perverse combinations of commands given in a very fast
  93.     sequence will produce strange characters.
  94.  
  95.     This is usually called from 'edline()'
  96.  
  97.     The maximum line length is 78 - strlen(prompt)
  98.  
  99. =============================================================================*/
  100. int edit(buf, prompt)
  101. char *buf;
  102. char *prompt;
  103. {
  104. unsigned char    
  105.     *ps=0,        /* start of buffer */
  106.     *pe=0,        /* end of buffer */
  107.     *pc=0,        /* current place in buffer */
  108.     *cp=0,        /* a 'current pointer' used in manipulations */
  109.     bell = '\007',  /* BEEEEP!! */
  110.     c = 0,        /* a temporary character holder */
  111.     curback='\b',    /* backspace */
  112.     gotofront = '\r', /* plain return */
  113.     newline = '\n', /* plain newline */
  114.     space = ' ';    /* space */
  115.  
  116. enum {first, next} time = next; /* for first time only things */
  117.  
  118. int    
  119.     char_count = 0,
  120.     eof = 0,
  121.     erase_char = 0,
  122.     fieldlen = 0,
  123.     jmpret,
  124.     maxlen = 78 - strlen(prompt);
  125.  
  126. struct termio no_canon, canon;
  127.  
  128. /*
  129.  * flush standard in and out so that any 'printf' or previous stdin
  130.  * requests are cleared out
  131.  */
  132.     fflush(stdin);
  133.     fflush(stdout);
  134. /*
  135.  * set terminal for prompt input
  136.  */
  137.     ioctl(0, TCGETA, &canon);
  138.     no_canon = canon;
  139.  
  140.     erase_char = canon.c_cc[2];
  141.     eof = canon.c_cc[4];
  142.  
  143.     no_canon.c_lflag &= ~(ICANON|ECHO|ECHOE);
  144.     no_canon.c_cc[4] = 1;
  145.     no_canon.c_cc[5] = 0;
  146.  
  147.     ioctl(0, TCSETAW, &no_canon);
  148. /*
  149.  * handle sigint sigquit
  150.  */
  151.     oldintsig = sigset(SIGINT, sig_handle);
  152.     oldquitsig = sigset(SIGQUIT, sig_handle); 
  153.  
  154.     if( (jmpret = setjmp(jumpbuf)) != 0 )
  155.     {
  156.         if(jmpret == SIGINT)
  157.             c = 255;
  158.         if(jmpret == SIGQUIT)
  159.             c = 254;
  160.         goto abort;
  161.     }
  162. /*
  163.  * edit buffer
  164.  */
  165.  
  166. /* DISPLAY BUFFER */
  167.  
  168.     PROMPT;
  169.     if( *buf )
  170.     {
  171.         fieldlen = char_count = strlen(buf);
  172.         write(1,buf,char_count);
  173.         if( lastlen > fieldlen )
  174.             write(1,spaces,lastlen-fieldlen);
  175.         write(1,&gotofront,1);
  176.         PROMPT;
  177.         if( *buf == ' ' )
  178.         {
  179.             *buf = '\0';
  180.             char_count = 0;
  181.             time = first;
  182.         }
  183.     }
  184.     else
  185.         time = first;
  186. /*
  187.  * set pointers
  188.  */
  189.     pc = ps = (unsigned char *)buf;
  190.     pe = ps + strlen(buf);
  191.  
  192.  
  193.     for(;;)
  194.     {
  195. /* 
  196.  * prime the pump by forcing 'insert' mode if this is the first time
  197.  * in the editor.
  198.  */
  199.         if( time == first )
  200.         {
  201.             c = 'i';
  202.             time = next;
  203.         }
  204.         else
  205.             read(0, &c, 1);
  206.  
  207.         switch(c)
  208.         {
  209. /* EXIT EDITING */
  210.         case '\n':
  211.             goto abort;
  212.             break;
  213.  
  214. /* END OF LINE */
  215.         case '$':
  216.             fieldlen = pe-(pc+1);
  217.             write(1,pc,fieldlen);
  218.             pc+=fieldlen;
  219.             break;
  220.  
  221. /* BEGINNING OF LINE */
  222.         case '0':
  223.             write(1, &gotofront, 1); 
  224.             PROMPT;
  225.             pc = ps;
  226.             break;
  227.  
  228. /* MOVE LEFT */
  229.         case 'h':
  230.             if( pc>ps )
  231.             {
  232.                 CURBACK;
  233.                 pc--;
  234.             }
  235.             else
  236.                 BELL;
  237.             break;
  238.  
  239. /* INSERT MODE */
  240. /*
  241.  * yes, there's some yank and put code here. shoot me
  242.  */
  243.         case 'a':
  244.             if(*ps != '\0')
  245.                 write(1, pc++, 1);
  246.  
  247.         /* NO BREAK HERE -- FALL THRU */
  248.  
  249.         case 'i':
  250.             for(;;)
  251.             {
  252.                 read(0, &c, 1);
  253.  
  254.     /* END INSERT MODE */
  255.                 if( c == ESC )
  256.                 {
  257.                     if( pc > ps)
  258.                     {
  259.                         pc--;
  260.                         CURBACK;
  261.                     }
  262.                     break;
  263.                 }
  264.     /* DELETE CHARACTER WITHIN INSERT MODE */
  265.                 else if( c == erase_char )
  266.                 {
  267.                     if( *ps == '\0' || pc <= ps )
  268.                     {
  269.                         pc = ps;
  270.                         BELL;
  271.                         continue;
  272.                     }
  273.                     else
  274.                     {
  275.                         pc--;
  276.                         CURBACK;
  277.                     }
  278.  
  279.                     for(cp = pc; *cp != '\0'; cp++)
  280.                     {
  281.                         *cp = *(cp+1);
  282.                     }
  283.  
  284.                     fieldlen=pe-pc;
  285.                     if(fieldlen)
  286.                         write(1,pc,fieldlen-1);
  287.                     SPACE;
  288.                     write(1,backspaces,fieldlen);
  289.  
  290.                     pe--;
  291.                     char_count--;
  292.                 }
  293.     /* EXIT EDITING FROM INSERT MODE */
  294.                 else if ( c == '\n' )
  295.                     goto abort;
  296.     /* GATHER CHARS IN INSERT MODE */
  297.                 else if( isalnum(c) || ispunct(c) || c == ' ' )
  298.                 {
  299.                     if( ++char_count >= maxlen )
  300.                     {
  301.                         BELL;
  302.                         char_count--;
  303.                         continue;
  304.                     }
  305.                     for(cp = pe; cp >= pc; cp--)
  306.                     {
  307.                         *(cp+1) = *cp;
  308.                     }
  309.                     *pc = c;
  310.  
  311.                     fieldlen=(pe-pc);
  312.                     write(1,pc,fieldlen+1);
  313.                     pc++;
  314.                     write(1,backspaces,fieldlen);
  315.  
  316.                     pe++;
  317.                 }
  318.             }
  319.             break;
  320.  
  321. /* UP, DOWN A LINE -- command character returned to 'edline()' */
  322.         case 'j':
  323.         case 'k':
  324.             goto abort;
  325.             break;
  326.  
  327. /* MOVE RIGHT */
  328.         case 'l':
  329.         case ' ':
  330.  
  331.             if( *(pc+1) == '\0' )
  332.                 BELL;
  333.             else
  334.             {
  335.                 write(1, pc, 1);
  336.                 pc++;
  337.             }
  338.             break;
  339.  
  340. /* FORWARD A WORD */
  341.         case 'w':
  342.             if( (pc+1) == pe )
  343.                 break;
  344.             else
  345.             {
  346.                 do
  347.                     write(1, pc++, 1);
  348.                 while( isalnum(*pc) && *(pc+1) != '\0' );
  349.                 if( *(pc+1) != '\0' )
  350.                     write(1, pc++, 1);
  351.             }
  352.             break;
  353.  
  354. /* BACKWARD A WORD */
  355.         case 'b':
  356.             if( pc <= ps )
  357.             {
  358.                 pc = ps;
  359.                 break;
  360.             }
  361.             else
  362.             {
  363.                 do
  364.                 {
  365.                     CURBACK;
  366.                     pc--;
  367.                 }
  368.                 while( isalnum(*pc) && pc > ps );
  369.                 if( pc > ps )
  370.                 {
  371.                     CURBACK;
  372.                     pc--;
  373.                 }
  374.             }
  375.             break;
  376.                 
  377. /* DELETE A CHAR */
  378.         case 'x':
  379.             if( *ps == '\0' || pc < ps )
  380.             {
  381.                 pc = ps;
  382.                 BELL;
  383.                 break;
  384.             }
  385.  
  386.             for(cp = pc; *cp != '\0'; cp++)
  387.             {
  388.                 *cp = *(cp+1);
  389.             }
  390.  
  391.  
  392.  
  393.             fieldlen=pe-pc;
  394.             if(fieldlen)
  395.                 write(1,pc,fieldlen-1);
  396.             SPACE;
  397.             write(1,backspaces,fieldlen);
  398.  
  399.             pe--;
  400.             char_count--;
  401.  
  402.             if( pc >= pe )
  403.             {
  404.                 pc--;
  405.                 if( pc >= ps )
  406.                     CURBACK;
  407.             }
  408.  
  409.             break;
  410.  
  411. /* REPLACE A CHAR */
  412.         case 'r':
  413.             read(0, &c, 1);
  414.             if( c != ESC )
  415.             {
  416.                 *pc = c;
  417.                 write(1, pc, 1);
  418.                 write(1,backspaces,1);
  419.             }
  420.             break;
  421.  
  422. /* ERROR */
  423.         default:
  424.             BELL;
  425.             break;
  426.         }
  427.     }
  428. abort:
  429. /*
  430.  * clean up and return 
  431.  */
  432.     write(1, &gotofront, 1); 
  433.     ioctl(0, TCSETAW, &canon);
  434.     sigset(SIGINT, oldintsig);
  435.     sigset(SIGQUIT, oldquitsig);
  436.  
  437.     lastlen=strlen(buf);
  438.     return c;
  439. }
  440.  
  441. static void sig_handle(sig)
  442. {
  443.     longjmp(jumpbuf, sig);
  444. }
  445.