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