]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/history.def
92094d68445dfe82d0af774df749277b305df248
[thirdparty/bash.git] / builtins / history.def
1 This file is history.def, from which is created history.c.
2 It implements the builtin "history" in Bash.
3
4 Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 1, or (at your option) any later
11 version.
12
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 $PRODUCES history.c
23
24 $BUILTIN history
25 $FUNCTION history_builtin
26 $DEPENDS_ON HISTORY
27 $SHORT_DOC history [-c] [n] or history -awrn [filename] or history -ps arg [arg...]
28 Display the history list with line numbers. Lines listed with
29 with a `*' have been modified. Argument of N says to list only
30 the last N lines. The -c option causes the history list to be
31 cleared by deleting all of the entries. The `-w' option writes out the
32 current history to the history file; `-r' means to read the file and
33 append the contents to the history list instead. `-a' means
34 to append history lines from this session to the history file.
35 Argument `-n' means to read all history lines not already read
36 from the history file and append them to the history list. If
37 FILENAME is given, then that is used as the history file else
38 if $HISTFILE has a value, that is used, else ~/.bash_history.
39 If the -s option is supplied, the non-option ARGs are appended to
40 the history list as a single entry. The -p option means to perform
41 history expansion on each ARG and display the result, without storing
42 anything in the history list.
43 $END
44
45 #include <config.h>
46
47 #if defined (HISTORY)
48 #include "../bashtypes.h"
49 #ifndef _MINIX
50 # include <sys/file.h>
51 #endif
52 #include "../posixstat.h"
53 #include "../filecntl.h"
54 #include <errno.h>
55 #include <stdio.h>
56 #if defined (HAVE_UNISTD_H)
57 # include <unistd.h>
58 #endif
59
60 #include "../bashansi.h"
61
62 #include "../shell.h"
63 #include "../bashhist.h"
64 #include <readline/history.h>
65 #include "bashgetopt.h"
66 #include "common.h"
67
68 #if !defined (errno)
69 extern int errno;
70 #endif
71
72 static void display_history ();
73 static void push_history ();
74 static int expand_and_print_history ();
75
76 #define AFLAG 0x01
77 #define RFLAG 0x02
78 #define WFLAG 0x04
79 #define NFLAG 0x08
80 #define SFLAG 0x10
81 #define PFLAG 0x20
82 #define CFLAG 0x40
83
84 int
85 history_builtin (list)
86 WORD_LIST *list;
87 {
88 int flags, opt, result;
89 char *filename;
90
91 flags = 0;
92 reset_internal_getopt ();
93 while ((opt = internal_getopt (list, "acnpsrw")) != -1)
94 {
95 switch (opt)
96 {
97 case 'a':
98 flags |= AFLAG;
99 break;
100 case 'c':
101 flags |= CFLAG;
102 break;
103 case 'n':
104 flags |= NFLAG;
105 break;
106 case 'r':
107 flags |= RFLAG;
108 break;
109 case 'w':
110 flags |= WFLAG;
111 break;
112 case 's':
113 flags |= SFLAG;
114 break;
115 case 'p':
116 #if defined (BANG_HISTORY)
117 flags |= PFLAG;
118 #endif
119 break;
120 default:
121 builtin_usage ();
122 return (EX_USAGE);
123 }
124 }
125 list = loptend;
126
127 opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG);
128 if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG)
129 {
130 builtin_error ("cannot use more than one of -anrw");
131 return (EXECUTION_FAILURE);
132 }
133
134 /* clear the history, but allow other arguments to add to it again. */
135 if (flags & CFLAG)
136 {
137 clear_history ();
138 if (list == 0)
139 return (EXECUTION_SUCCESS);
140 }
141
142 if (flags & SFLAG)
143 {
144 if (list)
145 push_history (list);
146 return (EXECUTION_SUCCESS);
147 }
148 #if defined (BANG_HISTORY)
149 else if (flags & PFLAG)
150 {
151 if (list)
152 return (expand_and_print_history (list));
153 return (EXECUTION_SUCCESS);
154 }
155 #endif
156 else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0)
157 {
158 display_history (list);
159 return (EXECUTION_SUCCESS);
160 }
161
162 filename = list ? list->word->word : get_string_value ("HISTFILE");
163 result = EXECUTION_SUCCESS;
164
165 if (flags & AFLAG) /* Append session's history to file. */
166 result = maybe_append_history (filename);
167 else if (flags & WFLAG) /* Write entire history. */
168 result = write_history (filename);
169 else if (flags & RFLAG) /* Read entire file. */
170 result = read_history (filename);
171 else if (flags & NFLAG) /* Read `new' history from file. */
172 {
173 /* Read all of the lines in the file that we haven't already read. */
174 using_history ();
175 result = read_history_range (filename, history_lines_in_file, -1);
176 using_history ();
177 history_lines_in_file = where_history ();
178 }
179
180 return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
181 }
182
183 /* Accessors for HIST_ENTRY lists that are called HLIST. */
184 #define histline(i) (hlist[(i)]->line)
185 #define histdata(i) (hlist[(i)]->data)
186
187 static void
188 display_history (list)
189 WORD_LIST *list;
190 {
191 register int i;
192 int limited, limit;
193 HIST_ENTRY **hlist;
194
195 if (list)
196 {
197 limited = 1;
198 limit = get_numeric_arg (list, 0);
199 }
200 else
201 limited = limit = 0;
202
203 hlist = history_list ();
204
205 if (hlist)
206 {
207 for (i = 0; hlist[i]; i++)
208 ;
209
210 if (limit < 0)
211 limit = -limit;
212
213 if ((limited == 0) || ((i -= limit) < 0))
214 i = 0;
215
216 while (hlist[i])
217 {
218 QUIT;
219 printf ("%5d%c %s\n", i + history_base,
220 histdata(i) ? '*' : ' ',
221 histline(i));
222 i++;
223 }
224 }
225 }
226
227 static int
228 delete_last_history ()
229 {
230 register int i;
231 HIST_ENTRY **hlist, *histent, *discard;
232
233 hlist = history_list ();
234 if (hlist == NULL)
235 return 0;
236
237 for (i = 0; hlist[i]; i++)
238 ;
239 i--;
240
241 /* History_get () takes a parameter that must be offset by history_base. */
242 histent = history_get (history_base + i); /* Don't free this */
243 if (histent == NULL)
244 return 0;
245
246 discard = remove_history (i);
247 if (discard)
248 {
249 if (discard->line)
250 free (discard->line);
251 free ((char *) discard);
252 }
253 return (1);
254 }
255
256 /* Remove the last entry in the history list and add each argument in
257 LIST to the history. */
258 static void
259 push_history (list)
260 WORD_LIST *list;
261 {
262 char *s;
263
264 if (hist_last_line_added && delete_last_history () == 0)
265 return;
266 s = string_list (list);
267 maybe_add_history (s); /* Obeys HISTCONTROL setting. */
268 free (s);
269 }
270
271 #if defined (BANG_HISTORY)
272 static int
273 expand_and_print_history (list)
274 WORD_LIST *list;
275 {
276 char *s;
277 int r, result;
278
279 if (hist_last_line_added && delete_last_history () == 0)
280 return EXECUTION_FAILURE;
281 result = EXECUTION_SUCCESS;
282 while (list)
283 {
284 r = history_expand (list->word->word, &s);
285 if (r < 0)
286 {
287 builtin_error ("%s: history expansion failed", list->word->word);
288 result = EXECUTION_FAILURE;
289 }
290 else
291 {
292 fputs (s, stdout);
293 putchar ('\n');
294 }
295 FREE (s);
296 list = list->next;
297 }
298 fflush (stdout);
299 return result;
300 }
301 #endif /* BANG_HISTORY */
302 #endif /* HISTORY */