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