1 /* $NetBSD: tc1.c,v 1.5 2010/04/18 21:17:47 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Christos Zoulas of Cornell University. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "config.h" 36 37 /* 38 * test.c: A little test program 39 */ 40 #include <sys/wait.h> 41 #include <ctype.h> 42 #include <dirent.h> 43 #include <locale.h> 44 #include <signal.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 #include "histedit.h" 51 52 static int continuation = 0; 53 volatile sig_atomic_t gotsig = 0; 54 55 static unsigned char complete(EditLine *, int); 56 int main(int, char **); 57 static char *prompt(EditLine *); 58 static void sig(int); 59 60 static char * 61 prompt(EditLine *el) 62 { 63 static char a[] = "\1\033[7m\1Edit$\1\033[0m\1 "; 64 static char b[] = "Edit> "; 65 66 return (continuation ? b : a); 67 } 68 69 static void 70 sig(int i) 71 { 72 gotsig = i; 73 } 74 75 static unsigned char 76 complete(EditLine *el, int ch) 77 { 78 DIR *dd = opendir("."); 79 struct dirent *dp; 80 const char* ptr; 81 const LineInfo *lf = el_line(el); 82 int len; 83 int res = CC_ERROR; 84 85 /* 86 * Find the last word 87 */ 88 for (ptr = lf->cursor - 1; 89 !isspace((unsigned char)*ptr) && ptr > lf->buffer; ptr--) 90 continue; 91 len = lf->cursor - ptr; 92 93 for (dp = readdir(dd); dp != NULL; dp = readdir(dd)) { 94 if (len > strlen(dp->d_name)) 95 continue; 96 if (strncmp(dp->d_name, ptr, len) == 0) { 97 if (el_insertstr(el, &dp->d_name[len]) == -1) 98 res = CC_ERROR; 99 else 100 res = CC_REFRESH; 101 break; 102 } 103 } 104 105 closedir(dd); 106 return res; 107 } 108 109 int 110 main(int argc, char *argv[]) 111 { 112 EditLine *el = NULL; 113 int num; 114 const char *buf; 115 Tokenizer *tok; 116 #if 0 117 int lastevent = 0; 118 #endif 119 int ncontinuation; 120 History *hist; 121 HistEvent ev; 122 123 (void) setlocale(LC_CTYPE, ""); 124 (void) signal(SIGINT, sig); 125 (void) signal(SIGQUIT, sig); 126 (void) signal(SIGHUP, sig); 127 (void) signal(SIGTERM, sig); 128 129 hist = history_init(); /* Init the builtin history */ 130 /* Remember 100 events */ 131 history(hist, &ev, H_SETSIZE, 100); 132 133 tok = tok_init(NULL); /* Initialize the tokenizer */ 134 135 /* Initialize editline */ 136 el = el_init(*argv, stdin, stdout, stderr); 137 138 el_set(el, EL_EDITOR, "vi"); /* Default editor is vi */ 139 el_set(el, EL_SIGNAL, 1); /* Handle signals gracefully */ 140 el_set(el, EL_PROMPT_ESC, prompt, '\1');/* Set the prompt function */ 141 142 /* Tell editline to use this history interface */ 143 el_set(el, EL_HIST, history, hist); 144 145 /* Add a user-defined function */ 146 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", complete); 147 148 /* Bind tab to it */ 149 el_set(el, EL_BIND, "^I", "ed-complete", NULL); 150 151 /* 152 * Bind j, k in vi command mode to previous and next line, instead 153 * of previous and next history. 154 */ 155 el_set(el, EL_BIND, "-a", "k", "ed-prev-line", NULL); 156 el_set(el, EL_BIND, "-a", "j", "ed-next-line", NULL); 157 158 /* 159 * Source the user's defaults file. 160 */ 161 el_source(el, NULL); 162 163 while ((buf = el_gets(el, &num)) != NULL && num != 0) { 164 int ac, cc, co; 165 #ifdef DEBUG 166 int i; 167 #endif 168 const char **av; 169 const LineInfo *li; 170 li = el_line(el); 171 #ifdef DEBUG 172 (void) fprintf(stderr, "==> got %d %s", num, buf); 173 (void) fprintf(stderr, " > li `%.*s_%.*s'\n", 174 (li->cursor - li->buffer), li->buffer, 175 (li->lastchar - 1 - li->cursor), 176 (li->cursor >= li->lastchar) ? "" : li->cursor); 177 178 #endif 179 if (gotsig) { 180 (void) fprintf(stderr, "Got signal %d.\n", gotsig); 181 gotsig = 0; 182 el_reset(el); 183 } 184 185 if (!continuation && num == 1) 186 continue; 187 188 ac = cc = co = 0; 189 ncontinuation = tok_line(tok, li, &ac, &av, &cc, &co); 190 if (ncontinuation < 0) { 191 (void) fprintf(stderr, "Internal error\n"); 192 continuation = 0; 193 continue; 194 } 195 #ifdef DEBUG 196 (void) fprintf(stderr, " > nc %d ac %d cc %d co %d\n", 197 ncontinuation, ac, cc, co); 198 #endif 199 #if 0 200 if (continuation) { 201 /* 202 * Append to the right event in case the user 203 * moved around in history. 204 */ 205 if (history(hist, &ev, H_SET, lastevent) == -1) 206 err(1, "%d: %s", lastevent, ev.str); 207 history(hist, &ev, H_ADD , buf); 208 } else { 209 history(hist, &ev, H_ENTER, buf); 210 lastevent = ev.num; 211 } 212 #else 213 /* Simpler */ 214 history(hist, &ev, continuation ? H_APPEND : H_ENTER, buf); 215 #endif 216 217 continuation = ncontinuation; 218 ncontinuation = 0; 219 if (continuation) 220 continue; 221 #ifdef DEBUG 222 for (i = 0; i < ac; i++) { 223 (void) fprintf(stderr, " > arg# %2d ", i); 224 if (i != cc) 225 (void) fprintf(stderr, "`%s'\n", av[i]); 226 else 227 (void) fprintf(stderr, "`%.*s_%s'\n", 228 co, av[i], av[i] + co); 229 } 230 #endif 231 232 if (strcmp(av[0], "history") == 0) { 233 int rv; 234 235 switch (ac) { 236 case 1: 237 for (rv = history(hist, &ev, H_LAST); rv != -1; 238 rv = history(hist, &ev, H_PREV)) 239 (void) fprintf(stdout, "%4d %s", 240 ev.num, ev.str); 241 break; 242 243 case 2: 244 if (strcmp(av[1], "clear") == 0) 245 history(hist, &ev, H_CLEAR); 246 else 247 goto badhist; 248 break; 249 250 case 3: 251 if (strcmp(av[1], "load") == 0) 252 history(hist, &ev, H_LOAD, av[2]); 253 else if (strcmp(av[1], "save") == 0) 254 history(hist, &ev, H_SAVE, av[2]); 255 break; 256 257 badhist: 258 default: 259 (void) fprintf(stderr, 260 "Bad history arguments\n"); 261 break; 262 } 263 } else if (el_parse(el, ac, av) == -1) { 264 switch (fork()) { 265 case 0: 266 execvp(av[0], (char *const *)av); 267 perror(av[0]); 268 _exit(1); 269 /*NOTREACHED*/ 270 break; 271 272 case -1: 273 perror("fork"); 274 break; 275 276 default: 277 if (wait(&num) == -1) 278 perror("wait"); 279 (void) fprintf(stderr, "Exit %x\n", num); 280 break; 281 } 282 } 283 284 tok_reset(tok); 285 } 286 287 el_end(el); 288 tok_end(tok); 289 history_end(hist); 290 291 return (0); 292 } 293