1
/* $NetBSD: histedit.c,v 1.34 2003/10/27 06:19:29 lukem Exp $ */
5
* The Regents of the University of California. All rights reserved.
7
* This code is derived from software contributed to Berkeley by
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
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.
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
36
#include <sys/cdefs.h>
43
static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95";
45
__RCSID("$NetBSD: histedit.c,v 1.34 2003/10/27 06:19:29 lukem Exp $");
49
#include <sys/param.h>
57
* Editline and history functions (and glue).
67
#ifdef KLIBC_SH_HISTORY
68
#include "myhistedit.h"
73
#include "compat_linux.h"
76
#define MAXHISTLOOPS 4 /* max recursions through fc */
77
#define DEFEDITOR "ed" /* default editor *should* be $EDITOR */
79
History *hist; /* history cookie */
80
EditLine *el; /* editline cookie */
82
static FILE *el_in, *el_out;
84
STATIC const char *fc_replace(const char *, char *, char *);
87
extern FILE *tracefile;
91
* Set history and editing status. Called whenever the status may
92
* have changed (figures out what to do).
99
#define editing (Eflag || Vflag)
107
hist = history_init();
111
sethistsize(histsizeval());
113
out2str("sh: can't initialize history\n");
115
if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
123
el_in = fdopen(0, "r");
125
el_out = fdopen(2, "w");
126
if (el_in == NULL || el_out == NULL)
133
term = lookupvar("TERM");
135
setenv("TERM", term, 1);
139
if (shname[0] == '-')
141
el = el_init(shname, el_in, el_out, el_err);
144
el_set(el, EL_HIST, history, hist);
145
el_set(el, EL_PROMPT, getprompt);
146
el_set(el, EL_SIGNAL, 1);
149
out2str("sh: can't initialize editing\n");
152
} else if (!editing && el) {
160
el_set(el, EL_EDITOR, "vi");
162
el_set(el, EL_EDITOR, "emacs");
167
if (el) { /* no editing if not interactive */
181
sethistsize(const char *hs)
187
if (hs == NULL || *hs == '\0' ||
188
(histsize = atoi(hs)) < 0)
190
history(hist, &he, H_SETSIZE, histsize);
195
setterm(const char *term)
197
if (el != NULL && term != NULL)
198
if (el_set(el, EL_TERMINAL, term) != 0) {
199
outfmt(out2, "sh: Can't set terminal type %s\n", term);
200
outfmt(out2, "sh: Using dumb terminal settings.\n");
210
out2str("usage: inputrc file\n");
214
if (el_source(el, argv[1])) {
215
out2str("inputrc: failed\n");
220
out2str("sh: inputrc ignored, not editing\n");
226
* This command is provided since POSIX decided to standardize
227
* the Korn shell fc command. Oh well...
230
histcmd(int argc, char **argv)
233
const char *editor = NULL;
235
int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
237
const char *firststr, *laststr;
238
int first, last, direction;
239
char *pat = NULL, *repl; /* ksh "fc old=new" crap */
240
static int active = 0;
241
struct jmploc jmploc;
242
struct jmploc *volatile savehandler;
243
char editfile[MAXPATHLEN + 1];
246
/* Avoid longjmp clobbering */
262
error("history not active");
265
error("missing history argument");
268
optreset = 1; /* initialize getopt */
270
optind = 1; /* initialize getopt */
271
while (not_fcnumber(argv[optind]) &&
272
(ch = getopt(argc, argv, ":e:lnrs")) != -1)
290
error("option -%c expects argument", optopt);
294
error("unknown option: -%c", optopt);
297
argc -= optind, argv += optind;
302
if (lflg == 0 || editor || sflg) {
303
lflg = 0; /* ignore */
306
* Catch interrupts to reset active counter and
307
* cleanup temp files.
309
if (setjmp(jmploc.loc)) {
313
handler = savehandler;
314
longjmp(handler->loc, 1);
316
savehandler = handler;
318
if (++active > MAXHISTLOOPS) {
321
error("called recursively too many times");
327
if (editor == NULL &&
328
(editor = bltinlookup("FCEDIT", 1)) == NULL &&
329
(editor = bltinlookup("EDITOR", 1)) == NULL)
331
if (editor[0] == '-' && editor[1] == '\0') {
332
sflg = 1; /* no edit */
339
* If executing, parse [old=new] now
341
if (lflg == 0 && argc > 0 &&
342
((repl = strchr(argv[0], '=')) != NULL)) {
348
* determine [first] and [last]
352
firststr = lflg ? "-16" : "-1";
357
laststr = lflg ? "-1" : argv[0];
364
error("too many args");
368
* Turn into event numbers.
370
first = str_to_event(firststr, 0);
371
last = str_to_event(laststr, 1);
379
* XXX - this should not depend on the event numbers
380
* always increasing. Add sequence numbers or offset
381
* to the history element in next (diskbased) release.
383
direction = first < last ? H_PREV : H_NEXT;
386
* If editing, grab a temp file.
391
snprintf(editfile, sizeof(editfile), "%s_shXXXXXX", _PATH_TMP);
392
if ((fd = mkstemp(editfile)) < 0)
393
error("can't create temporary file %s", editfile);
394
if ((efp = fdopen(fd, "w")) == NULL) {
396
error("can't allocate stdio buffer for temp");
401
* Loop through selected history events. If listing or executing,
402
* do it now. Otherwise, put into temp file and call the editor
405
* The history interface needs rethinking, as the following
406
* convolutions will demonstrate.
408
history(hist, &he, H_FIRST);
409
retval = history(hist, &he, H_NEXT_EVENT, first);
410
for (;retval != -1; retval = history(hist, &he, direction)) {
413
out1fmt("%5d ", he.num);
416
const char *s = pat ?
417
fc_replace(he.str, pat, repl) : he.str;
424
evalstring(strcpy(stalloc(strlen(s) + 1), s), 0);
425
if (displayhist && hist) {
427
* XXX what about recursive and
430
history(hist, &he, H_ENTER, s);
436
* At end? (if we were to lose last, we'd sure be
446
editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
447
sprintf(editcmd, "%s %s", editor, editfile);
448
evalstring(editcmd, 0); /* XXX - should use no JC command */
450
readcmdfile(editfile); /* XXX - should read back - quick tst */
454
if (lflg == 0 && active > 0)
462
fc_replace(const char *s, char *p, char *r)
465
int plen = strlen(p);
469
if (*s == *p && strncmp(s, p, plen) == 0) {
473
*p = '\0'; /* so no more matches */
478
dest = grabstackstr(dest);
484
not_fcnumber(char *s)
490
return (!is_number(s));
494
str_to_event(const char *str, int last)
501
retval = history(hist, &he, H_FIRST);
512
while (retval != -1 && i--) {
513
retval = history(hist, &he, H_NEXT);
516
retval = history(hist, &he, H_LAST);
518
retval = history(hist, &he, H_NEXT_EVENT, i);
521
* the notion of first and last is
522
* backwards to that of the history package
524
retval = history(hist, &he,
525
last ? H_FIRST : H_LAST);
529
error("history number %s not found (internal error)",
535
retval = history(hist, &he, H_PREV_STR, str);
537
error("history pattern not found: %s", str);
541
#endif /* KLIBC_SH_HISTORY */