Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/dash/histedit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1122 - (hide annotations) (download)
Wed Aug 18 21:11:40 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 10743 byte(s)
-updated to klibc-1.5.19
1 niro 532 /*-
2     * Copyright (c) 1993
3     * The Regents of the University of California. All rights reserved.
4     * Copyright (c) 1997-2005
5     * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
6     *
7     * This code is derived from software contributed to Berkeley by
8     * Kenneth Almquist.
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 <sys/param.h>
36     #include <paths.h>
37     #include <stdio.h>
38     #include <stdlib.h>
39     #include <unistd.h>
40     /*
41     * Editline and history functions (and glue).
42     */
43     #include "shell.h"
44     #include "parser.h"
45     #include "var.h"
46     #include "options.h"
47     #include "main.h"
48     #include "output.h"
49     #include "mystring.h"
50     #include "error.h"
51     #ifndef SMALL
52     #include "myhistedit.h"
53     #include "eval.h"
54     #include "memalloc.h"
55    
56     #define MAXHISTLOOPS 4 /* max recursions through fc */
57     #define DEFEDITOR "ed" /* default editor *should* be $EDITOR */
58    
59     History *hist; /* history cookie */
60     EditLine *el; /* editline cookie */
61     int displayhist;
62     static FILE *el_in, *el_out;
63    
64     STATIC const char *fc_replace(const char *, char *, char *);
65    
66     #ifdef DEBUG
67     extern FILE *tracefile;
68     #endif
69    
70     /*
71     * Set history and editing status. Called whenever the status may
72     * have changed (figures out what to do).
73     */
74     void
75     histedit(void)
76     {
77     FILE *el_err;
78    
79     #define editing (Eflag || Vflag)
80    
81     if (iflag) {
82     if (!hist) {
83     /*
84     * turn history on
85     */
86     INTOFF;
87     hist = history_init();
88     INTON;
89    
90     if (hist != NULL)
91     sethistsize(histsizeval());
92     else
93     out2str("sh: can't initialize history\n");
94     }
95     if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
96     /*
97     * turn editing on
98     */
99     INTOFF;
100     if (el_in == NULL)
101     el_in = fdopen(0, "r");
102     if (el_out == NULL)
103     el_out = fdopen(2, "w");
104     if (el_in == NULL || el_out == NULL)
105     goto bad;
106     el_err = el_out;
107     #if DEBUG
108     if (tracefile)
109     el_err = tracefile;
110     #endif
111     el = el_init(arg0, el_in, el_out, el_err);
112     if (el != NULL) {
113     if (hist)
114     el_set(el, EL_HIST, history, hist);
115     el_set(el, EL_PROMPT, getprompt);
116     } else {
117     bad:
118     out2str("sh: can't initialize editing\n");
119     }
120     INTON;
121     } else if (!editing && el) {
122     INTOFF;
123     el_end(el);
124     el = NULL;
125     INTON;
126     }
127     if (el) {
128     if (Vflag)
129     el_set(el, EL_EDITOR, "vi");
130     else if (Eflag)
131     el_set(el, EL_EDITOR, "emacs");
132     el_source(el, NULL);
133     }
134     } else {
135     INTOFF;
136     if (el) { /* no editing if not interactive */
137     el_end(el);
138     el = NULL;
139     }
140     if (hist) {
141     history_end(hist);
142     hist = NULL;
143     }
144     INTON;
145     }
146     }
147    
148    
149     void
150     sethistsize(const char *hs)
151     {
152     int histsize;
153     HistEvent he;
154    
155     if (hist != NULL) {
156     if (hs == NULL || *hs == '\0' ||
157     (histsize = atoi(hs)) < 0)
158     histsize = 100;
159     history(hist, &he, H_SETSIZE, histsize);
160     }
161     }
162    
163     void
164     setterm(const char *term)
165     {
166     if (el != NULL && term != NULL)
167     if (el_set(el, EL_TERMINAL, term) != 0) {
168     outfmt(out2, "sh: Can't set terminal type %s\n", term);
169     outfmt(out2, "sh: Using dumb terminal settings.\n");
170     }
171     }
172    
173     /*
174     * This command is provided since POSIX decided to standardize
175     * the Korn shell fc command. Oh well...
176     */
177     int
178     histcmd(int argc, char **argv)
179     {
180     int ch;
181     const char *editor = NULL;
182     HistEvent he;
183     int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
184     int i, retval;
185     const char *firststr, *laststr;
186     int first, last, direction;
187     char *pat = NULL, *repl; /* ksh "fc old=new" crap */
188     static int active = 0;
189     struct jmploc jmploc;
190     struct jmploc *volatile savehandler;
191     char editfile[MAXPATHLEN + 1];
192     FILE *efp;
193     #ifdef __GNUC__
194     /* Avoid longjmp clobbering */
195     (void) &editor;
196     (void) &lflg;
197     (void) &nflg;
198     (void) &rflg;
199     (void) &sflg;
200     (void) &firststr;
201     (void) &laststr;
202     (void) &pat;
203     (void) &repl;
204     (void) &efp;
205     (void) &argc;
206     (void) &argv;
207     #endif
208    
209     if (hist == NULL)
210     sh_error("history not active");
211    
212     if (argc == 1)
213     sh_error("missing history argument");
214    
215     #ifdef __GLIBC__
216     optind = 0;
217     #else
218     optreset = 1; optind = 1; /* initialize getopt */
219     #endif
220     while (not_fcnumber(argv[optind]) &&
221     (ch = getopt(argc, argv, ":e:lnrs")) != -1)
222     switch ((char)ch) {
223     case 'e':
224     editor = optionarg;
225     break;
226     case 'l':
227     lflg = 1;
228     break;
229     case 'n':
230     nflg = 1;
231     break;
232     case 'r':
233     rflg = 1;
234     break;
235     case 's':
236     sflg = 1;
237     break;
238     case ':':
239     sh_error("option -%c expects argument", optopt);
240     /* NOTREACHED */
241     case '?':
242     default:
243     sh_error("unknown option: -%c", optopt);
244     /* NOTREACHED */
245     }
246     argc -= optind, argv += optind;
247    
248     /*
249     * If executing...
250     */
251     if (lflg == 0 || editor || sflg) {
252     lflg = 0; /* ignore */
253     editfile[0] = '\0';
254     /*
255     * Catch interrupts to reset active counter and
256     * cleanup temp files.
257     */
258     if (setjmp(jmploc.loc)) {
259     active = 0;
260     if (*editfile)
261     unlink(editfile);
262     handler = savehandler;
263     longjmp(handler->loc, 1);
264     }
265     savehandler = handler;
266     handler = &jmploc;
267     if (++active > MAXHISTLOOPS) {
268     active = 0;
269     displayhist = 0;
270     sh_error("called recursively too many times");
271     }
272     /*
273     * Set editor.
274     */
275     if (sflg == 0) {
276     if (editor == NULL &&
277     (editor = bltinlookup("FCEDIT")) == NULL &&
278     (editor = bltinlookup("EDITOR")) == NULL)
279     editor = DEFEDITOR;
280     if (editor[0] == '-' && editor[1] == '\0') {
281     sflg = 1; /* no edit */
282     editor = NULL;
283     }
284     }
285     }
286    
287     /*
288     * If executing, parse [old=new] now
289     */
290     if (lflg == 0 && argc > 0 &&
291     ((repl = strchr(argv[0], '=')) != NULL)) {
292     pat = argv[0];
293     *repl++ = '\0';
294     argc--, argv++;
295     }
296     /*
297     * determine [first] and [last]
298     */
299     switch (argc) {
300     case 0:
301     firststr = lflg ? "-16" : "-1";
302     laststr = "-1";
303     break;
304     case 1:
305     firststr = argv[0];
306     laststr = lflg ? "-1" : argv[0];
307     break;
308     case 2:
309     firststr = argv[0];
310     laststr = argv[1];
311     break;
312     default:
313     sh_error("too many args");
314     /* NOTREACHED */
315     }
316     /*
317     * Turn into event numbers.
318     */
319     first = str_to_event(firststr, 0);
320     last = str_to_event(laststr, 1);
321    
322     if (rflg) {
323     i = last;
324     last = first;
325     first = i;
326     }
327     /*
328     * XXX - this should not depend on the event numbers
329     * always increasing. Add sequence numbers or offset
330     * to the history element in next (diskbased) release.
331     */
332     direction = first < last ? H_PREV : H_NEXT;
333    
334     /*
335     * If editing, grab a temp file.
336     */
337     if (editor) {
338     int fd;
339     INTOFF; /* easier */
340     sprintf(editfile, "%s_shXXXXXX", _PATH_TMP);
341     if ((fd = mkstemp(editfile)) < 0)
342     sh_error("can't create temporary file %s", editfile);
343     if ((efp = fdopen(fd, "w")) == NULL) {
344     close(fd);
345     sh_error("can't allocate stdio buffer for temp");
346     }
347     }
348    
349     /*
350     * Loop through selected history events. If listing or executing,
351     * do it now. Otherwise, put into temp file and call the editor
352     * after.
353     *
354     * The history interface needs rethinking, as the following
355     * convolutions will demonstrate.
356     */
357     history(hist, &he, H_FIRST);
358     retval = history(hist, &he, H_NEXT_EVENT, first);
359     for (;retval != -1; retval = history(hist, &he, direction)) {
360     if (lflg) {
361     if (!nflg)
362     out1fmt("%5d ", he.num);
363     out1str(he.str);
364     } else {
365     const char *s = pat ?
366     fc_replace(he.str, pat, repl) : he.str;
367    
368     if (sflg) {
369     if (displayhist) {
370     out2str(s);
371     }
372    
373     evalstring(strcpy(stalloc(strlen(s) + 1), s),
374 niro 1122 0);
375 niro 532 if (displayhist && hist) {
376     /*
377     * XXX what about recursive and
378     * relative histnums.
379     */
380     history(hist, &he, H_ENTER, s);
381     }
382     } else
383     fputs(s, efp);
384     }
385     /*
386     * At end? (if we were to lose last, we'd sure be
387     * messed up).
388     */
389     if (he.num == last)
390     break;
391     }
392     if (editor) {
393     char *editcmd;
394    
395     fclose(efp);
396     editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
397     sprintf(editcmd, "%s %s", editor, editfile);
398     /* XXX - should use no JC command */
399 niro 1122 evalstring(editcmd, 0);
400 niro 532 INTON;
401     readcmdfile(editfile); /* XXX - should read back - quick tst */
402     unlink(editfile);
403     }
404    
405     if (lflg == 0 && active > 0)
406     --active;
407     if (displayhist)
408     displayhist = 0;
409     return 0;
410     }
411    
412     STATIC const char *
413     fc_replace(const char *s, char *p, char *r)
414     {
415     char *dest;
416     int plen = strlen(p);
417    
418     STARTSTACKSTR(dest);
419     while (*s) {
420     if (*s == *p && strncmp(s, p, plen) == 0) {
421     while (*r)
422     STPUTC(*r++, dest);
423     s += plen;
424     *p = '\0'; /* so no more matches */
425     } else
426     STPUTC(*s++, dest);
427     }
428     STACKSTRNUL(dest);
429     dest = grabstackstr(dest);
430    
431     return (dest);
432     }
433    
434     int
435     not_fcnumber(char *s)
436     {
437     if (s == NULL)
438     return 0;
439     if (*s == '-')
440     s++;
441     return (!is_number(s));
442     }
443    
444     int
445     str_to_event(const char *str, int last)
446     {
447     HistEvent he;
448     const char *s = str;
449     int relative = 0;
450     int i, retval;
451    
452     retval = history(hist, &he, H_FIRST);
453     switch (*s) {
454     case '-':
455     relative = 1;
456     /*FALLTHROUGH*/
457     case '+':
458     s++;
459     }
460     if (is_number(s)) {
461     i = atoi(s);
462     if (relative) {
463     while (retval != -1 && i--) {
464     retval = history(hist, &he, H_NEXT);
465     }
466     if (retval == -1)
467     retval = history(hist, &he, H_LAST);
468     } else {
469     retval = history(hist, &he, H_NEXT_EVENT, i);
470     if (retval == -1) {
471     /*
472     * the notion of first and last is
473     * backwards to that of the history package
474     */
475     retval = history(hist, &he,
476     last ? H_FIRST : H_LAST);
477     }
478     }
479     if (retval == -1)
480     sh_error("history number %s not found (internal error)",
481     str);
482     } else {
483     /*
484     * pattern
485     */
486     retval = history(hist, &he, H_PREV_STR, str);
487     if (retval == -1)
488     sh_error("history pattern not found: %s", str);
489     }
490     return (he.num);
491     }
492     #endif