]> pd.if.org Git - pd_readline/blob - pd_readline.c
b4b886efa8ef540bb510ffbed48c4a55ebf1141c
[pd_readline] / pd_readline.c
1
2
3 /*  pd_readline.c                                      */  
4 /*  Some code to allow the editing of a command-line.  */ 
5 /*  You can also move around with the left and right   */ 
6 /*  arrow keys, and recall previous commands with the  */ 
7 /*  up-arrow key.                                      */ 
8 /*  This code is released to the public domain.        */ 
9 /*  "Share and enjoy...."  ;)                          */  
10 /*  See the UNLICENSE file for details.                */ 
11
12 /*  TO DO -                                            */ 
13 /*  a) Add support for Home and End (of line) keys.    */ 
14 /*  b) Add support for function keys.                  */ 
15 /*  c) Add support for Insert key so that text can be  */ 
16 /*     inserted.                                       */   
17 /*  d) Put much of the code into a header file.        */    
18 /*  e) Change so that pressing Enter adds the current  */  
19 /*     line of commands to the command-history.        */ 
20 /*     ( May look at using Ctrl-D to exit, as Python   */ 
21 /*     does with its command-line. )                   */           
22 /*  f) Add support for copying and pasting text via    */ 
23 /*     Ctrl-C and Ctrl-V.                              */  
24
25
26 #include <string.h>   
27 #include <stdio.h> 
28 #include <termios.h>  
29
30 /* This implementation of getch() is from here - */ 
31 /* http://wesley.vidiqatch.org/                  */ 
32 /* Thanks, Wesley!                               */  
33 static struct termios old, new;
34
35 /* Initialize new terminal i/o settings */
36 void initTermios(int echo) {
37     tcgetattr(0, &old); /* grab old terminal i/o settings */
38     new = old; /* make new settings same as old settings */
39     new.c_lflag &= ~ICANON; /* disable buffered i/o */
40     new.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
41     tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
42 }
43
44
45 /* Restore old terminal i/o settings */
46 void resetTermios(void) {
47     tcsetattr(0, TCSANOW, &old);
48 }
49
50
51 /* Read 1 character - echo defines echo mode */
52 char getch_(int echo) {
53     char ch;
54     initTermios(echo);
55     ch = getchar();
56     resetTermios();
57     return ch;
58 }
59
60
61 /* Read 1 character without echo */
62 char getch(void) {
63     return getch_(0);
64 }
65
66
67 /* Read 1 character with echo */
68 char getche(void) {
69     return getch_(1);
70
71
72
73
74 /*  Helper function, to let us see if a file */ 
75 /*  exists in the current directory.  */ 
76 int fexists(char *fname)
77 {  
78    FILE *fptr;  
79    fptr = fopen(fname, "r") ;     
80    if ( !fptr )  return -1 ;  /* File does not exist in dir. */                  
81    fclose(fptr);  
82    return 0;    /* File DOES exist in dir.  */   
83
84
85
86 /* Helper function to chop newlines off the lines read in. */ 
87 /* Without this being done, an extra newline is inserted */ 
88 /* (which is usually not what is wanted). */ 
89 char *chop(char *s)
90 {
91   s[strcspn(s,"\n")] = '\0'; 
92   return s; 
93 }
94
95
96 /* An array to store the command-history file in. */ 
97 /* Only 20 lines are read. */ 
98 char hist[20][80];  
99
100
101
102 /* Read the file into the array of strings.  */ 
103 void readfile(char *fname) 
104
105    int retval = fexists(fname); 
106         
107    int i; 
108    if (retval == 0) { 
109           /* File exists, so open it. */  
110           /* We open it in read-write mode so we can */ 
111           /* append new commands to it. */ 
112           FILE *fptr;  
113           fptr = fopen(fname, "rw"); 
114                            
115           for(i=0; i<20; i++)  
116           {  
117                 chop(fgets(hist[i], 80, fptr) );  
118           }
119           
120    }  /* retval == 0  */           
121         
122         else puts("Error! File does not exist. \n");  
123         
124 }       
125
126
127 /* Helper function to print the command-history file. */  
128 void printfile(void) 
129
130   int j; 
131         
132   for(j=0; j<20; j++) 
133      { 
134         puts(hist[j]);          
135      }          
136 }       
137
138
139
140
141 /* Helper function. Print a previous command-line WITHOUT */ 
142 /* a newline. */ 
143 void putline(char *str) 
144 {   
145   char *line = chop(str);       
146   printf("%s", line);                   
147 }        
148
149
150
151
152 int main(void) 
153
154
155 /* Our "command-history" file.  */ 
156 readfile("test.txt"); 
157
158       
159 /* "Pointer" for the history file. */ 
160 int histpnt = 20;       
161       
162   
163   while(1) 
164     {  
165                    
166       int key = getch();               
167        
168       /* Printable chars. */  
169       if ( (key >= 32)  && (key <= 126) ) 
170       { 
171                 /* We have a printable key so print it. */   
172                 putchar(key);           
173       }  
174                                                                        
175       /* Up arrow is 27, 91, 65.    ( ESC [ A )   */   
176       /* Down arrow is 27, 91, 66.  ( ESC [ B )   */ 
177       /* Right arrow is 27, 91, 67. ( ESC [ C )   */ 
178       /* Left arrow is 27, 91, 68.  ( ESC [ D )   */    
179       /* Function keys.     */ 
180       /* F2 is 27, 79, 81.  */  
181       /* F3 is 27, 79, 82.  */  
182       /* F4 is 27, 79, 83.  */  
183       
184       /* Backspace */ 
185       else if(key == 127) 
186       { 
187                  /* Move left 1 char and delete that char */            
188                  printf("\033[1D");
189                  printf("\040"); 
190                  printf("\033[1D");                              
191           }           
192         
193      /* We have an escape key-sequence */                           
194       else if(key == 27) 
195         {
196            key = getch(); 
197            if(key == 91)               
198            key = getch(); 
199            
200            if (key == 65)   /* Up Arrow */ 
201           {   
202                           /* Move one command "back" in history. */  
203                           histpnt -= 1;                                                         
204                           /* Clear to end of line. */ 
205                           printf("\033[80D"); 
206                           printf("\033[K");                      
207                           /* Print the pointed-at command-sequence. */ 
208                           putline(hist[histpnt]);                        
209           }  
210           
211           if(key == 66)    /* Down Arrow */                       
212                   {  
213                           /* Move one command "forward" in history. */  
214                           histpnt += 1;                                                                                  
215                           /* Clear to end of line. */ 
216                           printf("\033[80D"); 
217                           printf("\033[K");                                              
218                           /* Print the pointed-at command-sequence. */ 
219                           putline(hist[histpnt]);                         
220                   }  
221                   
222                   if(key == 67)  /* Left arrow */ 
223           {     
224                          /* Move one character to the left. */                           
225                           printf("\033[1C"); 
226           }
227           
228           if(key == 68)  /* Right arrow */ 
229           {     
230                         /* Move one character to the right. */                                    
231                           printf("\033[1D"); 
232           }
233                                                         
234       }  /* End of key=27 key sequence. */ 
235                                                                                                                    
236                                                  
237      /* The Enter key exits. Enter is 10 decimal */       
238         else if(key == 10)  
239                 { 
240                          puts("\n");  
241                          puts("Exiting... \n");                                                                                 
242              break;           
243          }  /* Key = Enter */   
244     }                
245                                       
246         return 0;
247
248 }  
249
250
251
252
253
254