]> pd.if.org Git - pd_readline/blobdiff - pd_readline.c
Getting close to a basic working readline now.
[pd_readline] / pd_readline.c
index 168a860a11d7929a4c19421c8f0e84b787178557..5bf04dc7d8715e2388ebb8fb247653535c522a95 100644 (file)
-\r
-\r
-/*  pd_readline.c                                           */  \r
-/*  Status (as at 26th Aug 2012) : useful progress.         */ \r
-/*  Keystroke sequences (along with the special flags       */ \r
-/*  like Esc, Ctrl, Alt etc are now stored in a buffer      */ \r
-/*  ( an array of structs ).                                */    \r
-/*  It will still be some time before this is a REAL        */ \r
-/*  readline, but we are "on the way"......                 */     \r
-/*  This code is released to the public domain.             */ \r
-/*  "Share and enjoy...."  ;)                               */  \r
-\r
-\r
-#include <string.h>   \r
-#include <stdio.h> \r
-#include <termios.h>  /* For getch()  */  \r
-\r
-/* This implementation of getch() is from here - */ \r
-/* http://wesley.vidiqatch.org/                  */ \r
-/* Thanks, Wesley!                               */  \r
-static struct termios old, new;\r
-\r
-/* Initialize new terminal i/o settings */\r
-void initTermios(int echo) {\r
-    tcgetattr(0, &old); /* grab old terminal i/o settings */\r
-    new = old; /* make new settings same as old settings */\r
-    new.c_lflag &= ~ICANON; /* disable buffered i/o */\r
-    new.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */\r
-    tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */\r
-}\r
-\r
-\r
-/* Restore old terminal i/o settings */\r
-void resetTermios(void) {\r
-    tcsetattr(0, TCSANOW, &old);\r
-}\r
-\r
-\r
-/* Read 1 character - echo defines echo mode */\r
-char getch_(int echo) {\r
-    char ch;\r
-    initTermios(echo);\r
-    ch = getchar();\r
-    resetTermios();\r
-    return ch;\r
-}\r
-\r
-\r
-/* Read 1 character without echo */\r
-char getch(void) {\r
-    return getch_(0);\r
-}\r
-\r
-\r
-/* Read 1 character with echo */\r
-char getche(void) {\r
-    return getch_(1);\r
-} \r
-\r
-\r
-\r
-/*  Helper function, to let us see if a .history file */ \r
-/*  exists in the current directory.  */ \r
-int fexists(char *fname)\r
-{  \r
-\r
-   FILE *fptr ;        \r
-       \r
-   fptr = fopen(fname, "r") ;  \r
-   \r
-   if ( !fptr )  return -1 ;  /* File does not exist in dir. */        \r
-        \r
-   fclose(fptr);  \r
-   return 0;    /* File DOES exist in dir.  */         \r
-\r
-} \r
-\r
-\r
- /* Struct to store key sequences */ \r
-typedef struct { \r
-          int fnkey; \r
-          int ctrl; \r
-          int alt ; \r
-       int shf ; \r
-       int esc ; \r
-       int lbr ;  /* For left-bracket ([) of escape sequences */ \r
-       int key; \r
-   } keyseq ;         \r
-\r
-\r
-\r
-\r
-\r
-int main(void)\r
-{\r
-       \r
-  printf("Public Domain Readline \n");              \r
-  printf("NOTE! - at the moment, we are using \n");  \r
-  printf("NON-echoing reads, storing the keystrokes \n");  \r
-  printf("in a buffer \n");   \r
-    \r
-  \r
-  /* Buffer - an array of keyseq structs.                     */  \r
-  /* Note - now that we store the keystrokes in here,         */ \r
-  /* we can look at the various flags and decide whether to   */ \r
-  /* "echo" the key (as normal) or suppress it (as with an    */ \r
-  /* arrow key).                                              */    \r
-  keyseq buffer[80] ;   \r
-  \r
-  /* Buffer "pointer"  */ \r
-  int bufpnt = 0; \r
-  \r
-  \r
-  /* Test for existence of history file. */  \r
-  int exists;  \r
-  exists = fexists(".history"); \r
-  printf("Result: %d \n", exists);  \r
-  \r
-  while(1) \r
-    {  \r
-                   \r
-      int key = getch(); \r
-       \r
-      /* Printable chars. */  \r
-      if ( (key >= 32)  && (key <= 126) ) \r
-      {                \r
-        buffer[bufpnt].key = key;  \r
-        bufpnt += 1; \r
-      }  \r
-                                                                       \r
-      /* Up arrow is 27, 91, 65.    ( ESC [ A )   */   \r
-      /* Down arrow is 27, 91, 66.  ( ESC [ B )   */ \r
-      /* Right arrow is 27, 91, 67. ( ESC [ C )   */ \r
-      /* Left arrow is 27, 91, 68.  ( ESC [ D )   */    \r
-      /* Function keys.     */ \r
-      /* F2 is 27, 79, 81.  */  \r
-      /* F3 is 27, 79, 82.  */  \r
-      /* F4 is 27, 79, 83.  */  \r
-           \r
-                \r
-      else if(key == 27)        \r
-          {  \r
-                         \r
-                         buffer[bufpnt].esc = 1;                        \r
-                         key = getch(); \r
-              if(key == 91)               \r
-              buffer[bufpnt].lbr = 1;                \r
-              key = getch(); \r
-              if( (key >= 65) && (key <= 68) )  \r
-               {                                \r
-                                buffer[bufpnt].key = key;                  \r
-               }                                 \r
-            bufpnt += 1;           \r
-          } \r
-              \r
-                                          \r
-                                                 \r
-    /* The Enter key exits. Enter is 10 decimal */       \r
-        else if(key == 10)  \r
-               { \r
-                        int j ; \r
-                  /* Print the array of structs. */ \r
-                    for (j=0; j<10; j++)       \r
-                    { \r
-                           printf("Fnkey: %d ", buffer[j].fnkey  ) ; \r
-                           printf("Ctrl:  %d ", buffer[j].ctrl   ) ;   \r
-                           printf("Alt:   %d ", buffer[j].alt    ) ; \r
-                           printf("Shf:   %d ", buffer[j].shf    ) ; \r
-                           printf("Esc:   %d ", buffer[j].esc    ) ; \r
-                           printf("Lbr:   %d ", buffer[j].lbr    ) ;  \r
-                   printf("Key:   %d \n", buffer[j].key  ) ; \r
-                }                      \r
-                                         \r
-             break;           \r
-         }  /* Key = Enter */   \r
-    }                \r
-                                      \r
-       return 0;\r
-}  \r
-\r
-\r
-\r
-\r
+
+
+/*  pd_readline.c                                      */  
+/*  Some code to allow the editing of a command-line.  */ 
+/*  You can also move around with the left and right   */ 
+/*  arrow keys, and recall previous commands with the  */ 
+/*  up-arrow key.                                      */ 
+/*  This code is released to the public domain.        */ 
+/*  "Share and enjoy...."  ;)                          */  
+
+
+#include <string.h>   
+#include <stdio.h> 
+#include <termios.h>  
+
+/* This implementation of getch() is from here - */ 
+/* http://wesley.vidiqatch.org/                  */ 
+/* Thanks, Wesley!                               */  
+static struct termios old, new;
+
+/* Initialize new terminal i/o settings */
+void initTermios(int echo) {
+    tcgetattr(0, &old); /* grab old terminal i/o settings */
+    new = old; /* make new settings same as old settings */
+    new.c_lflag &= ~ICANON; /* disable buffered i/o */
+    new.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
+    tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
+}
+
+
+/* Restore old terminal i/o settings */
+void resetTermios(void) {
+    tcsetattr(0, TCSANOW, &old);
+}
+
+
+/* Read 1 character - echo defines echo mode */
+char getch_(int echo) {
+    char ch;
+    initTermios(echo);
+    ch = getchar();
+    resetTermios();
+    return ch;
+}
+
+
+/* Read 1 character without echo */
+char getch(void) {
+    return getch_(0);
+}
+
+
+/* Read 1 character with echo */
+char getche(void) {
+    return getch_(1);
+} 
+
+
+
+/*  Helper function, to let us see if a file */ 
+/*  exists in the current directory.  */ 
+int fexists(char *fname)
+{  
+   FILE *fptr;  
+   fptr = fopen(fname, "r") ;     
+   if ( !fptr )  return -1 ;  /* File does not exist in dir. */                 
+   fclose(fptr);  
+   return 0;    /* File DOES exist in dir.  */   
+} 
+
+
+/* Helper function to chop newlines off the lines read in. */ 
+/* Without this being done, an extra newline is inserted */ 
+/* (which is usually not what is wanted). */ 
+char *chop(char *s)
+{
+  s[strcspn(s,"\n")] = '\0'; 
+  return s; 
+}
+
+
+/* An array to store the command-history file in. */ 
+/* Only 20 lines are read. */ 
+char hist[20][80];  
+
+
+/* Read the file into the array of strings.  */ 
+void readfile(char *fname) 
+{ 
+   int retval = fexists(fname); 
+        
+   int i; 
+   if (retval == 0) { 
+         /* File exists, so open it. */  
+         /* We open it in read-write mode so we can */ 
+         /* append new commands to it. */ 
+         FILE *fptr;  
+         fptr = fopen(fname, "rw"); 
+                          
+         for(i=0; i<20; i++)  
+         {  
+               chop(fgets(hist[i], 80, fptr) );  
+         }
+         
+   }  /* retval == 0  */          
+       
+       else puts("Error! File does not exist. \n");  
+       
+}      
+
+
+/* Helper function to print the command-history file. */  
+void printfile(void) 
+{ 
+  int j; 
+       
+  for(j=0; j<20; j++) 
+     { 
+        puts(hist[j]);         
+     }         
+}      
+
+
+
+
+/* Helper function. Print a previous command-line WITHOUT */ 
+/* a newline. */ 
+void putline(char *str) 
+{   
+  char *line = chop(str);      
+  printf("%s", line);                          
+}       
+
+
+
+
+int main(void) 
+{ 
+
+/* Our "command-history" file.  */ 
+readfile("test.txt"); 
+
+/* Main buffer for the command-line. */ 
+char buffer[80];  
+    
+/* Main buffer "pointer"  */ 
+int bufpnt = 0; 
+      
+/* "Pointer" for the history file. */ 
+int histpnt = 20;       
+      
+  
+  while(1) 
+    {  
+                   
+      int key = getch();      
+      buffer[bufpnt] = key;                                   
+      bufpnt += 1;        
+       
+      /* Printable chars. */  
+      if ( (key >= 32)  && (key <= 126) ) 
+      { 
+               /* We have a printable key so print it. */   
+               putchar(key);   
+               bufpnt += 1;            
+      }  
+                                                                       
+      /* Up arrow is 27, 91, 65.    ( ESC [ A )   */   
+      /* Down arrow is 27, 91, 66.  ( ESC [ B )   */ 
+      /* Right arrow is 27, 91, 67. ( ESC [ C )   */ 
+      /* Left arrow is 27, 91, 68.  ( ESC [ D )   */    
+      /* Function keys.     */ 
+      /* F2 is 27, 79, 81.  */  
+      /* F3 is 27, 79, 82.  */  
+      /* F4 is 27, 79, 83.  */  
+      
+      /* Backspace */ 
+      else if(key == 127) 
+      { 
+                /* Move left 1 char and delete that char */ 
+                bufpnt -= 1;   
+                printf("\033[1D");
+                printf("\040"); 
+                printf("\033[1D");              
+                /* Move 1 char to left again */  
+                bufpnt -= 1;           
+         }           
+        
+     /* We have an escape key-sequence */                           
+      else if(key == 27) 
+        {
+           key = getch(); 
+           if(key == 91)               
+           key = getch(); 
+           
+           if (key == 65)   /* Up Arrow */ 
+          {   
+                         /* Move one command "back" in history. */  
+                         histpnt -= 1;                                                         
+                         /* Clear to end of line. */ 
+                         printf("\033[80D"); 
+                         printf("\033[K"); 
+                         /* Move buffer pointer to start of line */ 
+                         bufpnt = 0;  
+                         /* Clear the array. */ 
+                         memset(buffer, 0, sizeof(char)*80);                                             
+                         /* Print the pointed-at command-sequence. */ 
+                         putline(hist[histpnt]);                        
+          }  
+          
+          if(key == 66)    /* Down Arrow */                      
+                 {  
+                         /* Move one command "forward" in history. */  
+                         histpnt += 1;                                                                                  
+                         /* Clear to end of line. */ 
+                         printf("\033[80D"); 
+                         printf("\033[K"); 
+                         /* Move buffer pointer to start of line */ 
+                         bufpnt = 0; 
+                         /* Clear the array. */ 
+                         memset(buffer, 0, sizeof(char)*80);                                                                     
+                         /* Print the pointed-at command-sequence. */ 
+                         putline(hist[histpnt]);                         
+                 }  
+                 
+                 if(key == 67)  /* Left arrow */ 
+          {    
+                        /* Move one character to the left. */                                                                    
+                         printf("\033[1C"); 
+          }
+          
+          if(key == 68)  /* Right arrow */ 
+          {    
+                       /* Move one character to the right. */                                                                                                                                                                   
+                         printf("\033[1D"); 
+          }
+                                                       
+      }  /* End of key=27 key sequence. */ 
+                                                                                                                  
+                                                 
+     /* The Enter key exits. Enter is 10 decimal */      
+        else if(key == 10)  
+               { 
+                        puts("\n");  
+                        puts("Exiting... \n");                                                                                 
+             break;           
+         }  /* Key = Enter */   
+    }                
+                                      
+       return 0;
+
+}  
+
+
+
+
+
+