Subversion Repositories HelenOS

Rev

Rev 2714 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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