Fri Jan 7 22:21:56 2011 UTC ()
Call el_source before initializing sh-specific editline properties (i.e.
the editor type and the tab completion binding).

This allows tab completion to work when a user has an ~/.editrc file.

Addresses PR bin/43404.


(jmmv)
diff -r1.41 -r1.42 src/bin/sh/histedit.c

cvs diff -r1.41 -r1.42 src/bin/sh/histedit.c (switch to unified diff)

--- src/bin/sh/histedit.c 2008/02/13 12:57:16 1.41
+++ src/bin/sh/histedit.c 2011/01/07 22:21:56 1.42
@@ -1,546 +1,546 @@ @@ -1,546 +1,546 @@
1/* $NetBSD: histedit.c,v 1.41 2008/02/13 12:57:16 joerg Exp $ */ 1/* $NetBSD: histedit.c,v 1.42 2011/01/07 22:21:56 jmmv Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1993 4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to Berkeley by 7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist. 8 * Kenneth Almquist.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors 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 19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission. 20 * without specific prior written permission.
21 * 21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 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 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 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 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 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE. 32 * SUCH DAMAGE.
33 */ 33 */
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36#ifndef lint 36#ifndef lint
37#if 0 37#if 0
38static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95"; 38static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95";
39#else 39#else
40__RCSID("$NetBSD: histedit.c,v 1.41 2008/02/13 12:57:16 joerg Exp $"); 40__RCSID("$NetBSD: histedit.c,v 1.42 2011/01/07 22:21:56 jmmv Exp $");
41#endif 41#endif
42#endif /* not lint */ 42#endif /* not lint */
43 43
44#include <sys/param.h> 44#include <sys/param.h>
45#include <paths.h> 45#include <paths.h>
46#include <stdio.h> 46#include <stdio.h>
47#include <stdlib.h> 47#include <stdlib.h>
48#include <unistd.h> 48#include <unistd.h>
49/* 49/*
50 * Editline and history functions (and glue). 50 * Editline and history functions (and glue).
51 */ 51 */
52#include "shell.h" 52#include "shell.h"
53#include "parser.h" 53#include "parser.h"
54#include "var.h" 54#include "var.h"
55#include "options.h" 55#include "options.h"
56#include "main.h" 56#include "main.h"
57#include "output.h" 57#include "output.h"
58#include "mystring.h" 58#include "mystring.h"
59#include "myhistedit.h" 59#include "myhistedit.h"
60#include "error.h" 60#include "error.h"
61#ifndef SMALL 61#ifndef SMALL
62#include "eval.h" 62#include "eval.h"
63#include "memalloc.h" 63#include "memalloc.h"
64 64
65#define MAXHISTLOOPS 4 /* max recursions through fc */ 65#define MAXHISTLOOPS 4 /* max recursions through fc */
66#define DEFEDITOR "ed" /* default editor *should* be $EDITOR */ 66#define DEFEDITOR "ed" /* default editor *should* be $EDITOR */
67 67
68History *hist; /* history cookie */ 68History *hist; /* history cookie */
69EditLine *el; /* editline cookie */ 69EditLine *el; /* editline cookie */
70int displayhist; 70int displayhist;
71static FILE *el_in, *el_out; 71static FILE *el_in, *el_out;
72unsigned char _el_fn_complete(EditLine *, int); 72unsigned char _el_fn_complete(EditLine *, int);
73 73
74STATIC const char *fc_replace(const char *, char *, char *); 74STATIC const char *fc_replace(const char *, char *, char *);
75 75
76#ifdef DEBUG 76#ifdef DEBUG
77extern FILE *tracefile; 77extern FILE *tracefile;
78#endif 78#endif
79 79
80/* 80/*
81 * Set history and editing status. Called whenever the status may 81 * Set history and editing status. Called whenever the status may
82 * have changed (figures out what to do). 82 * have changed (figures out what to do).
83 */ 83 */
84void 84void
85histedit(void) 85histedit(void)
86{ 86{
87 FILE *el_err; 87 FILE *el_err;
88 88
89#define editing (Eflag || Vflag) 89#define editing (Eflag || Vflag)
90 90
91 if (iflag == 1) { 91 if (iflag == 1) {
92 if (!hist) { 92 if (!hist) {
93 /* 93 /*
94 * turn history on 94 * turn history on
95 */ 95 */
96 INTOFF; 96 INTOFF;
97 hist = history_init(); 97 hist = history_init();
98 INTON; 98 INTON;
99 99
100 if (hist != NULL) 100 if (hist != NULL)
101 sethistsize(histsizeval()); 101 sethistsize(histsizeval());
102 else 102 else
103 out2str("sh: can't initialize history\n"); 103 out2str("sh: can't initialize history\n");
104 } 104 }
105 if (editing && !el && isatty(0)) { /* && isatty(2) ??? */ 105 if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
106 /* 106 /*
107 * turn editing on 107 * turn editing on
108 */ 108 */
109 char *term, *shname; 109 char *term, *shname;
110 110
111 INTOFF; 111 INTOFF;
112 if (el_in == NULL) 112 if (el_in == NULL)
113 el_in = fdopen(0, "r"); 113 el_in = fdopen(0, "r");
114 if (el_out == NULL) 114 if (el_out == NULL)
115 el_out = fdopen(2, "w"); 115 el_out = fdopen(2, "w");
116 if (el_in == NULL || el_out == NULL) 116 if (el_in == NULL || el_out == NULL)
117 goto bad; 117 goto bad;
118 el_err = el_out; 118 el_err = el_out;
119#if DEBUG 119#if DEBUG
120 if (tracefile) 120 if (tracefile)
121 el_err = tracefile; 121 el_err = tracefile;
122#endif 122#endif
123 term = lookupvar("TERM"); 123 term = lookupvar("TERM");
124 if (term) 124 if (term)
125 setenv("TERM", term, 1); 125 setenv("TERM", term, 1);
126 else 126 else
127 unsetenv("TERM"); 127 unsetenv("TERM");
128 shname = arg0; 128 shname = arg0;
129 if (shname[0] == '-') 129 if (shname[0] == '-')
130 shname++; 130 shname++;
131 el = el_init(shname, el_in, el_out, el_err); 131 el = el_init(shname, el_in, el_out, el_err);
132 if (el != NULL) { 132 if (el != NULL) {
133 if (hist) 133 if (hist)
134 el_set(el, EL_HIST, history, hist); 134 el_set(el, EL_HIST, history, hist);
135 el_set(el, EL_PROMPT, getprompt); 135 el_set(el, EL_PROMPT, getprompt);
136 el_set(el, EL_SIGNAL, 1); 136 el_set(el, EL_SIGNAL, 1);
137 el_set(el, EL_ADDFN, "rl-complete", 137 el_set(el, EL_ADDFN, "rl-complete",
138 "ReadLine compatible completion function", 138 "ReadLine compatible completion function",
139 _el_fn_complete); 139 _el_fn_complete);
140 } else { 140 } else {
141bad: 141bad:
142 out2str("sh: can't initialize editing\n"); 142 out2str("sh: can't initialize editing\n");
143 } 143 }
144 INTON; 144 INTON;
145 } else if (!editing && el) { 145 } else if (!editing && el) {
146 INTOFF; 146 INTOFF;
147 el_end(el); 147 el_end(el);
148 el = NULL; 148 el = NULL;
149 INTON; 149 INTON;
150 } 150 }
151 if (el) { 151 if (el) {
 152 el_source(el, NULL);
152 if (Vflag) 153 if (Vflag)
153 el_set(el, EL_EDITOR, "vi"); 154 el_set(el, EL_EDITOR, "vi");
154 else if (Eflag) 155 else if (Eflag)
155 el_set(el, EL_EDITOR, "emacs"); 156 el_set(el, EL_EDITOR, "emacs");
156 el_set(el, EL_BIND, "^I",  157 el_set(el, EL_BIND, "^I",
157 tabcomplete ? "rl-complete" : "ed-insert", NULL); 158 tabcomplete ? "rl-complete" : "ed-insert", NULL);
158 el_source(el, NULL); 
159 } 159 }
160 } else { 160 } else {
161 INTOFF; 161 INTOFF;
162 if (el) { /* no editing if not interactive */ 162 if (el) { /* no editing if not interactive */
163 el_end(el); 163 el_end(el);
164 el = NULL; 164 el = NULL;
165 } 165 }
166 if (hist) { 166 if (hist) {
167 history_end(hist); 167 history_end(hist);
168 hist = NULL; 168 hist = NULL;
169 } 169 }
170 INTON; 170 INTON;
171 } 171 }
172} 172}
173 173
174 174
175void 175void
176sethistsize(const char *hs) 176sethistsize(const char *hs)
177{ 177{
178 int histsize; 178 int histsize;
179 HistEvent he; 179 HistEvent he;
180 180
181 if (hist != NULL) { 181 if (hist != NULL) {
182 if (hs == NULL || *hs == '\0' || 182 if (hs == NULL || *hs == '\0' ||
183 (histsize = atoi(hs)) < 0) 183 (histsize = atoi(hs)) < 0)
184 histsize = 100; 184 histsize = 100;
185 history(hist, &he, H_SETSIZE, histsize); 185 history(hist, &he, H_SETSIZE, histsize);
186 history(hist, &he, H_SETUNIQUE, 1); 186 history(hist, &he, H_SETUNIQUE, 1);
187 } 187 }
188} 188}
189 189
190void 190void
191setterm(const char *term) 191setterm(const char *term)
192{ 192{
193 if (el != NULL && term != NULL) 193 if (el != NULL && term != NULL)
194 if (el_set(el, EL_TERMINAL, term) != 0) { 194 if (el_set(el, EL_TERMINAL, term) != 0) {
195 outfmt(out2, "sh: Can't set terminal type %s\n", term); 195 outfmt(out2, "sh: Can't set terminal type %s\n", term);
196 outfmt(out2, "sh: Using dumb terminal settings.\n"); 196 outfmt(out2, "sh: Using dumb terminal settings.\n");
197 } 197 }
198} 198}
199 199
200int 200int
201inputrc(argc, argv) 201inputrc(argc, argv)
202 int argc; 202 int argc;
203 char **argv; 203 char **argv;
204{ 204{
205 if (argc != 2) { 205 if (argc != 2) {
206 out2str("usage: inputrc file\n"); 206 out2str("usage: inputrc file\n");
207 return 1; 207 return 1;
208 } 208 }
209 if (el != NULL) { 209 if (el != NULL) {
210 if (el_source(el, argv[1])) { 210 if (el_source(el, argv[1])) {
211 out2str("inputrc: failed\n"); 211 out2str("inputrc: failed\n");
212 return 1; 212 return 1;
213 } else 213 } else
214 return 0; 214 return 0;
215 } else { 215 } else {
216 out2str("sh: inputrc ignored, not editing\n"); 216 out2str("sh: inputrc ignored, not editing\n");
217 return 1; 217 return 1;
218 } 218 }
219} 219}
220 220
221/* 221/*
222 * This command is provided since POSIX decided to standardize 222 * This command is provided since POSIX decided to standardize
223 * the Korn shell fc command. Oh well... 223 * the Korn shell fc command. Oh well...
224 */ 224 */
225int 225int
226histcmd(int argc, char **argv) 226histcmd(int argc, char **argv)
227{ 227{
228 int ch; 228 int ch;
229 const char * volatile editor = NULL; 229 const char * volatile editor = NULL;
230 HistEvent he; 230 HistEvent he;
231 int lflg = 0; 231 int lflg = 0;
232 volatile int nflg = 0, rflg = 0, sflg = 0; 232 volatile int nflg = 0, rflg = 0, sflg = 0;
233 int i, retval; 233 int i, retval;
234 const char *firststr, *laststr; 234 const char *firststr, *laststr;
235 int first, last, direction; 235 int first, last, direction;
236 char *pat = NULL, *repl; /* ksh "fc old=new" crap */ 236 char *pat = NULL, *repl; /* ksh "fc old=new" crap */
237 static int active = 0; 237 static int active = 0;
238 struct jmploc jmploc; 238 struct jmploc jmploc;
239 struct jmploc *volatile savehandler; 239 struct jmploc *volatile savehandler;
240 char editfile[MAXPATHLEN + 1]; 240 char editfile[MAXPATHLEN + 1];
241 FILE *efp; 241 FILE *efp;
242#ifdef __GNUC__ 242#ifdef __GNUC__
243 repl = NULL; /* XXX gcc4 */ 243 repl = NULL; /* XXX gcc4 */
244 efp = NULL; /* XXX gcc4 */ 244 efp = NULL; /* XXX gcc4 */
245#endif 245#endif
246 246
247 if (hist == NULL) 247 if (hist == NULL)
248 error("history not active"); 248 error("history not active");
249 249
250 if (argc == 1) 250 if (argc == 1)
251 error("missing history argument"); 251 error("missing history argument");
252 252
253 optreset = 1; optind = 1; /* initialize getopt */ 253 optreset = 1; optind = 1; /* initialize getopt */
254 while (not_fcnumber(argv[optind]) && 254 while (not_fcnumber(argv[optind]) &&
255 (ch = getopt(argc, argv, ":e:lnrs")) != -1) 255 (ch = getopt(argc, argv, ":e:lnrs")) != -1)
256 switch ((char)ch) { 256 switch ((char)ch) {
257 case 'e': 257 case 'e':
258 editor = optionarg; 258 editor = optionarg;
259 break; 259 break;
260 case 'l': 260 case 'l':
261 lflg = 1; 261 lflg = 1;
262 break; 262 break;
263 case 'n': 263 case 'n':
264 nflg = 1; 264 nflg = 1;
265 break; 265 break;
266 case 'r': 266 case 'r':
267 rflg = 1; 267 rflg = 1;
268 break; 268 break;
269 case 's': 269 case 's':
270 sflg = 1; 270 sflg = 1;
271 break; 271 break;
272 case ':': 272 case ':':
273 error("option -%c expects argument", optopt); 273 error("option -%c expects argument", optopt);
274 /* NOTREACHED */ 274 /* NOTREACHED */
275 case '?': 275 case '?':
276 default: 276 default:
277 error("unknown option: -%c", optopt); 277 error("unknown option: -%c", optopt);
278 /* NOTREACHED */ 278 /* NOTREACHED */
279 } 279 }
280 argc -= optind, argv += optind; 280 argc -= optind, argv += optind;
281 281
282 /* 282 /*
283 * If executing... 283 * If executing...
284 */ 284 */
285 if (lflg == 0 || editor || sflg) { 285 if (lflg == 0 || editor || sflg) {
286 lflg = 0; /* ignore */ 286 lflg = 0; /* ignore */
287 editfile[0] = '\0'; 287 editfile[0] = '\0';
288 /* 288 /*
289 * Catch interrupts to reset active counter and 289 * Catch interrupts to reset active counter and
290 * cleanup temp files. 290 * cleanup temp files.
291 */ 291 */
292 if (setjmp(jmploc.loc)) { 292 if (setjmp(jmploc.loc)) {
293 active = 0; 293 active = 0;
294 if (*editfile) 294 if (*editfile)
295 unlink(editfile); 295 unlink(editfile);
296 handler = savehandler; 296 handler = savehandler;
297 longjmp(handler->loc, 1); 297 longjmp(handler->loc, 1);
298 } 298 }
299 savehandler = handler; 299 savehandler = handler;
300 handler = &jmploc; 300 handler = &jmploc;
301 if (++active > MAXHISTLOOPS) { 301 if (++active > MAXHISTLOOPS) {
302 active = 0; 302 active = 0;
303 displayhist = 0; 303 displayhist = 0;
304 error("called recursively too many times"); 304 error("called recursively too many times");
305 } 305 }
306 /* 306 /*
307 * Set editor. 307 * Set editor.
308 */ 308 */
309 if (sflg == 0) { 309 if (sflg == 0) {
310 if (editor == NULL && 310 if (editor == NULL &&
311 (editor = bltinlookup("FCEDIT", 1)) == NULL && 311 (editor = bltinlookup("FCEDIT", 1)) == NULL &&
312 (editor = bltinlookup("EDITOR", 1)) == NULL) 312 (editor = bltinlookup("EDITOR", 1)) == NULL)
313 editor = DEFEDITOR; 313 editor = DEFEDITOR;
314 if (editor[0] == '-' && editor[1] == '\0') { 314 if (editor[0] == '-' && editor[1] == '\0') {
315 sflg = 1; /* no edit */ 315 sflg = 1; /* no edit */
316 editor = NULL; 316 editor = NULL;
317 } 317 }
318 } 318 }
319 } 319 }
320 320
321 /* 321 /*
322 * If executing, parse [old=new] now 322 * If executing, parse [old=new] now
323 */ 323 */
324 if (lflg == 0 && argc > 0 && 324 if (lflg == 0 && argc > 0 &&
325 ((repl = strchr(argv[0], '=')) != NULL)) { 325 ((repl = strchr(argv[0], '=')) != NULL)) {
326 pat = argv[0]; 326 pat = argv[0];
327 *repl++ = '\0'; 327 *repl++ = '\0';
328 argc--, argv++; 328 argc--, argv++;
329 } 329 }
330 330
331 /* 331 /*
332 * If -s is specified, accept only one operand 332 * If -s is specified, accept only one operand
333 */ 333 */
334 if (sflg && argc >= 2) 334 if (sflg && argc >= 2)
335 error("too many args"); 335 error("too many args");
336 336
337 /* 337 /*
338 * determine [first] and [last] 338 * determine [first] and [last]
339 */ 339 */
340 switch (argc) { 340 switch (argc) {
341 case 0: 341 case 0:
342 firststr = lflg ? "-16" : "-1"; 342 firststr = lflg ? "-16" : "-1";
343 laststr = "-1"; 343 laststr = "-1";
344 break; 344 break;
345 case 1: 345 case 1:
346 firststr = argv[0]; 346 firststr = argv[0];
347 laststr = lflg ? "-1" : argv[0]; 347 laststr = lflg ? "-1" : argv[0];
348 break; 348 break;
349 case 2: 349 case 2:
350 firststr = argv[0]; 350 firststr = argv[0];
351 laststr = argv[1]; 351 laststr = argv[1];
352 break; 352 break;
353 default: 353 default:
354 error("too many args"); 354 error("too many args");
355 /* NOTREACHED */ 355 /* NOTREACHED */
356 } 356 }
357 /* 357 /*
358 * Turn into event numbers. 358 * Turn into event numbers.
359 */ 359 */
360 first = str_to_event(firststr, 0); 360 first = str_to_event(firststr, 0);
361 last = str_to_event(laststr, 1); 361 last = str_to_event(laststr, 1);
362 362
363 if (rflg) { 363 if (rflg) {
364 i = last; 364 i = last;
365 last = first; 365 last = first;
366 first = i; 366 first = i;
367 } 367 }
368 /* 368 /*
369 * XXX - this should not depend on the event numbers 369 * XXX - this should not depend on the event numbers
370 * always increasing. Add sequence numbers or offset 370 * always increasing. Add sequence numbers or offset
371 * to the history element in next (diskbased) release. 371 * to the history element in next (diskbased) release.
372 */ 372 */
373 direction = first < last ? H_PREV : H_NEXT; 373 direction = first < last ? H_PREV : H_NEXT;
374 374
375 /* 375 /*
376 * If editing, grab a temp file. 376 * If editing, grab a temp file.
377 */ 377 */
378 if (editor) { 378 if (editor) {
379 int fd; 379 int fd;
380 INTOFF; /* easier */ 380 INTOFF; /* easier */
381 snprintf(editfile, sizeof(editfile), "%s_shXXXXXX", _PATH_TMP); 381 snprintf(editfile, sizeof(editfile), "%s_shXXXXXX", _PATH_TMP);
382 if ((fd = mkstemp(editfile)) < 0) 382 if ((fd = mkstemp(editfile)) < 0)
383 error("can't create temporary file %s", editfile); 383 error("can't create temporary file %s", editfile);
384 if ((efp = fdopen(fd, "w")) == NULL) { 384 if ((efp = fdopen(fd, "w")) == NULL) {
385 close(fd); 385 close(fd);
386 error("can't allocate stdio buffer for temp"); 386 error("can't allocate stdio buffer for temp");
387 } 387 }
388 } 388 }
389 389
390 /* 390 /*
391 * Loop through selected history events. If listing or executing, 391 * Loop through selected history events. If listing or executing,
392 * do it now. Otherwise, put into temp file and call the editor 392 * do it now. Otherwise, put into temp file and call the editor
393 * after. 393 * after.
394 * 394 *
395 * The history interface needs rethinking, as the following 395 * The history interface needs rethinking, as the following
396 * convolutions will demonstrate. 396 * convolutions will demonstrate.
397 */ 397 */
398 history(hist, &he, H_FIRST); 398 history(hist, &he, H_FIRST);
399 retval = history(hist, &he, H_NEXT_EVENT, first); 399 retval = history(hist, &he, H_NEXT_EVENT, first);
400 for (;retval != -1; retval = history(hist, &he, direction)) { 400 for (;retval != -1; retval = history(hist, &he, direction)) {
401 if (lflg) { 401 if (lflg) {
402 if (!nflg) 402 if (!nflg)
403 out1fmt("%5d ", he.num); 403 out1fmt("%5d ", he.num);
404 out1str(he.str); 404 out1str(he.str);
405 } else { 405 } else {
406 const char *s = pat ? 406 const char *s = pat ?
407 fc_replace(he.str, pat, repl) : he.str; 407 fc_replace(he.str, pat, repl) : he.str;
408 408
409 if (sflg) { 409 if (sflg) {
410 if (displayhist) { 410 if (displayhist) {
411 out2str(s); 411 out2str(s);
412 } 412 }
413 413
414 evalstring(strcpy(stalloc(strlen(s) + 1), s), 0); 414 evalstring(strcpy(stalloc(strlen(s) + 1), s), 0);
415 if (displayhist && hist) { 415 if (displayhist && hist) {
416 /* 416 /*
417 * XXX what about recursive and 417 * XXX what about recursive and
418 * relative histnums. 418 * relative histnums.
419 */ 419 */
420 history(hist, &he, H_ENTER, s); 420 history(hist, &he, H_ENTER, s);
421 } 421 }
422 422
423 break; 423 break;
424 } else 424 } else
425 fputs(s, efp); 425 fputs(s, efp);
426 } 426 }
427 /* 427 /*
428 * At end? (if we were to lose last, we'd sure be 428 * At end? (if we were to lose last, we'd sure be
429 * messed up). 429 * messed up).
430 */ 430 */
431 if (he.num == last) 431 if (he.num == last)
432 break; 432 break;
433 } 433 }
434 if (editor) { 434 if (editor) {
435 char *editcmd; 435 char *editcmd;
436 436
437 fclose(efp); 437 fclose(efp);
438 editcmd = stalloc(strlen(editor) + strlen(editfile) + 2); 438 editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
439 sprintf(editcmd, "%s %s", editor, editfile); 439 sprintf(editcmd, "%s %s", editor, editfile);
440 evalstring(editcmd, 0); /* XXX - should use no JC command */ 440 evalstring(editcmd, 0); /* XXX - should use no JC command */
441 INTON; 441 INTON;
442 readcmdfile(editfile); /* XXX - should read back - quick tst */ 442 readcmdfile(editfile); /* XXX - should read back - quick tst */
443 unlink(editfile); 443 unlink(editfile);
444 } 444 }
445 445
446 if (lflg == 0 && active > 0) 446 if (lflg == 0 && active > 0)
447 --active; 447 --active;
448 if (displayhist) 448 if (displayhist)
449 displayhist = 0; 449 displayhist = 0;
450 return 0; 450 return 0;
451} 451}
452 452
453STATIC const char * 453STATIC const char *
454fc_replace(const char *s, char *p, char *r) 454fc_replace(const char *s, char *p, char *r)
455{ 455{
456 char *dest; 456 char *dest;
457 int plen = strlen(p); 457 int plen = strlen(p);
458 458
459 STARTSTACKSTR(dest); 459 STARTSTACKSTR(dest);
460 while (*s) { 460 while (*s) {
461 if (*s == *p && strncmp(s, p, plen) == 0) { 461 if (*s == *p && strncmp(s, p, plen) == 0) {
462 while (*r) 462 while (*r)
463 STPUTC(*r++, dest); 463 STPUTC(*r++, dest);
464 s += plen; 464 s += plen;
465 *p = '\0'; /* so no more matches */ 465 *p = '\0'; /* so no more matches */
466 } else 466 } else
467 STPUTC(*s++, dest); 467 STPUTC(*s++, dest);
468 } 468 }
469 STACKSTRNUL(dest); 469 STACKSTRNUL(dest);
470 dest = grabstackstr(dest); 470 dest = grabstackstr(dest);
471 471
472 return (dest); 472 return (dest);
473} 473}
474 474
475int 475int
476not_fcnumber(char *s) 476not_fcnumber(char *s)
477{ 477{
478 if (s == NULL) 478 if (s == NULL)
479 return 0; 479 return 0;
480 if (*s == '-') 480 if (*s == '-')
481 s++; 481 s++;
482 return (!is_number(s)); 482 return (!is_number(s));
483} 483}
484 484
485int 485int
486str_to_event(const char *str, int last) 486str_to_event(const char *str, int last)
487{ 487{
488 HistEvent he; 488 HistEvent he;
489 const char *s = str; 489 const char *s = str;
490 int relative = 0; 490 int relative = 0;
491 int i, retval; 491 int i, retval;
492 492
493 retval = history(hist, &he, H_FIRST); 493 retval = history(hist, &he, H_FIRST);
494 switch (*s) { 494 switch (*s) {
495 case '-': 495 case '-':
496 relative = 1; 496 relative = 1;
497 /*FALLTHROUGH*/ 497 /*FALLTHROUGH*/
498 case '+': 498 case '+':
499 s++; 499 s++;
500 } 500 }
501 if (is_number(s)) { 501 if (is_number(s)) {
502 i = atoi(s); 502 i = atoi(s);
503 if (relative) { 503 if (relative) {
504 while (retval != -1 && i--) { 504 while (retval != -1 && i--) {
505 retval = history(hist, &he, H_NEXT); 505 retval = history(hist, &he, H_NEXT);
506 } 506 }
507 if (retval == -1) 507 if (retval == -1)
508 retval = history(hist, &he, H_LAST); 508 retval = history(hist, &he, H_LAST);
509 } else { 509 } else {
510 retval = history(hist, &he, H_NEXT_EVENT, i); 510 retval = history(hist, &he, H_NEXT_EVENT, i);
511 if (retval == -1) { 511 if (retval == -1) {
512 /* 512 /*
513 * the notion of first and last is 513 * the notion of first and last is
514 * backwards to that of the history package 514 * backwards to that of the history package
515 */ 515 */
516 retval = history(hist, &he, 516 retval = history(hist, &he,
517 last ? H_FIRST : H_LAST); 517 last ? H_FIRST : H_LAST);
518 } 518 }
519 } 519 }
520 if (retval == -1) 520 if (retval == -1)
521 error("history number %s not found (internal error)", 521 error("history number %s not found (internal error)",
522 str); 522 str);
523 } else { 523 } else {
524 /* 524 /*
525 * pattern 525 * pattern
526 */ 526 */
527 retval = history(hist, &he, H_PREV_STR, str); 527 retval = history(hist, &he, H_PREV_STR, str);
528 if (retval == -1) 528 if (retval == -1)
529 error("history pattern not found: %s", str); 529 error("history pattern not found: %s", str);
530 } 530 }
531 return (he.num); 531 return (he.num);
532} 532}
533#else 533#else
534int 534int
535histcmd(int argc, char **argv) 535histcmd(int argc, char **argv)
536{ 536{
537 error("not compiled with history support"); 537 error("not compiled with history support");
538 /* NOTREACHED */ 538 /* NOTREACHED */
539} 539}
540int 540int
541inputrc(int argc, char **argv) 541inputrc(int argc, char **argv)
542{ 542{
543 error("not compiled with history support"); 543 error("not compiled with history support");
544 /* NOTREACHED */ 544 /* NOTREACHED */
545} 545}
546#endif 546#endif