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