Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
BitchX
GitHub Repository: BitchX/BitchX1.3
Path: blob/master/source/history.c
1069 views
1
/*
2
* history.c: stuff to handle command line history
3
*
4
*
5
* Written By Michael Sandrof
6
*
7
* Copyright(c) 1990
8
*
9
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
10
*/
11
12
13
#include "irc.h"
14
static char cvsrevision[] = "$Id: history.c 3 2008-02-25 09:49:14Z keaston $";
15
CVS_REVISION(history_c)
16
#include "struct.h"
17
18
#include "ircaux.h"
19
#include "vars.h"
20
#include "history.h"
21
#include "output.h"
22
#include "input.h"
23
#define MAIN_SOURCE
24
#include "modval.h"
25
26
static char *history_match (char *);
27
static void add_to_history_list (int, char *);
28
static char *get_from_history_buffer (int);
29
30
typedef struct HistoryStru
31
{
32
int number;
33
char *stuff;
34
struct HistoryStru *next;
35
struct HistoryStru *prev;
36
} History;
37
38
/* command_history: pointer to head of command_history list */
39
static History *command_history_head = NULL;
40
static History *command_history_tail = NULL;
41
static History *command_history_pos = NULL;
42
43
/* hist_size: the current size of the command_history array */
44
static int hist_size = 0;
45
46
/* hist_count: the absolute counter for the history list */
47
static int hist_count = 0;
48
49
/*
50
* last_dir: the direction (next or previous) of the last get_from_history()
51
* call.... reset by add to history
52
*/
53
static int last_dir = -1;
54
55
/*
56
* history pointer
57
*/
58
static History *tmp = NULL;
59
60
/*
61
* history_match: using wild_match(), this finds the latest match in the
62
* history file and returns it as the function result. Returns null if there
63
* is no match. Note that this sticks a '*' at the end if one is not already
64
* there.
65
*/
66
static char *history_match (char *match)
67
{
68
char *ptr;
69
char *match_str = NULL;
70
71
if (*(match + strlen(match) - 1) == '*')
72
match_str = LOCAL_COPY(match);
73
else
74
{
75
match_str = alloca(strlen(match) + 3);
76
strcpy(match_str, match);
77
strcat(match_str, "*");
78
}
79
if (get_int_var(HISTORY_VAR))
80
{
81
if ((last_dir == -1) || (tmp == NULL))
82
tmp = command_history_head;
83
else
84
tmp = tmp->next;
85
if (tmp)
86
{
87
for (; tmp; tmp = tmp->next)
88
{
89
ptr = tmp->stuff;
90
while (ptr && strchr(get_string_var(CMDCHARS_VAR), *ptr))
91
ptr++;
92
93
if (wild_match(match_str, ptr))
94
{
95
last_dir = PREV;
96
return (tmp->stuff);
97
}
98
}
99
}
100
}
101
last_dir = -1;
102
return NULL;
103
}
104
105
/* shove_to_history: a key binding that saves the current line into
106
* the history and then deletes the whole line. Useful for when you
107
* are in the middle of a big line and need to "get out" to do something
108
* else quick for just a second, and you dont want to have to retype
109
* everything all over again
110
*/
111
extern void shove_to_history (char unused, char *not_used)
112
{
113
add_to_history(get_input());
114
input_clear_line(unused, not_used);
115
}
116
117
static void add_to_history_list(int cnt, char *stuff)
118
{
119
History *new;
120
121
if (get_int_var(HISTORY_VAR) == 0)
122
return;
123
if ((hist_size == get_int_var(HISTORY_VAR)) && command_history_tail)
124
{
125
if (hist_size == 1)
126
{
127
malloc_strcpy(&command_history_tail->stuff, stuff);
128
return;
129
}
130
new = command_history_tail;
131
command_history_tail = command_history_tail->prev;
132
command_history_tail->next = NULL;
133
new_free(&new->stuff);
134
new_free((char **)&new);
135
if (command_history_tail == NULL)
136
command_history_head = NULL;
137
}
138
else
139
hist_size++;
140
new = (History *) new_malloc(sizeof(History));
141
new->stuff = NULL;
142
new->number = cnt;
143
new->next = command_history_head;
144
new->prev = NULL;
145
malloc_strcpy(&(new->stuff), stuff);
146
if (command_history_head)
147
command_history_head->prev = new;
148
command_history_head = new;
149
if (command_history_tail == NULL)
150
command_history_tail = new;
151
command_history_pos = NULL;
152
}
153
154
/*
155
* set_history_size: adjusts the size of the command_history to be size. If
156
* the array is not yet allocated, it is set to size and all the entries
157
* nulled. If it exists, it is resized to the new size with a realloc. Any
158
* new entries are nulled.
159
*/
160
void set_history_size(Window *win, char *unused, int size)
161
{
162
int i,
163
cnt;
164
History *ptr;
165
166
if (size < hist_size)
167
{
168
cnt = hist_size - size;
169
for (i = 0; i < cnt; i++)
170
{
171
ptr = command_history_tail;
172
command_history_tail = ptr->prev;
173
new_free(&(ptr->stuff));
174
new_free((char **)&ptr);
175
}
176
if (command_history_tail == NULL)
177
command_history_head = NULL;
178
else
179
command_history_tail->next = NULL;
180
hist_size = size;
181
}
182
}
183
184
/*
185
* add_to_history: adds the given line to the history array. The history
186
* array is a circular buffer, and add_to_history handles all that stuff. It
187
* automagically allocted and deallocated memory as needed
188
*/
189
void add_to_history(char *line)
190
{
191
char *ptr;
192
193
if (line && *line)
194
{
195
while (line && *line)
196
{
197
if ((ptr = sindex(line, "\n\r")) != NULL)
198
*(ptr++) = '\0';
199
add_to_history_list(hist_count, line);
200
last_dir = PREV;
201
hist_count++;
202
line = ptr;
203
}
204
}
205
}
206
207
static char *get_from_history_buffer(int which)
208
{
209
if ((get_int_var(HISTORY_VAR) == 0) || (hist_size == 0))
210
return NULL;
211
/*
212
* if (last_dir != which) { last_dir = which; get_from_history(which); }
213
*/
214
if (which == NEXT)
215
{
216
if (command_history_pos)
217
{
218
if (command_history_pos->prev)
219
command_history_pos = command_history_pos->prev;
220
else
221
command_history_pos = command_history_tail;
222
}
223
else
224
{
225
add_to_history(get_input());
226
command_history_pos = command_history_tail;
227
}
228
return (command_history_pos->stuff);
229
}
230
else
231
{
232
if (command_history_pos)
233
{
234
if (command_history_pos->next)
235
command_history_pos = command_history_pos->next;
236
else
237
command_history_pos = command_history_head;
238
}
239
else
240
{
241
add_to_history(get_input());
242
command_history_pos = command_history_head;
243
}
244
return (command_history_pos->stuff);
245
}
246
}
247
248
/*
249
* get_history: gets the next history entry, either the PREV entry or the
250
* NEXT entry, and sets it to the current input string
251
*/
252
extern void get_history (int which)
253
{
254
char *ptr;
255
256
if ((ptr = get_from_history(which)) != NULL)
257
{
258
set_input(ptr);
259
update_input(UPDATE_ALL);
260
}
261
262
}
263
264
char *get_from_history(int which)
265
{
266
return(get_from_history_buffer(which));
267
}
268
269
/* history: the /HISTORY command, shows the command history buffer. */
270
BUILT_IN_COMMAND(history)
271
{
272
int cnt,
273
max = 0;
274
char *value;
275
char *match = NULL;
276
277
if (get_int_var(HISTORY_VAR))
278
{
279
say("Command History:");
280
if ((value = next_arg(args, &args)) != NULL)
281
{
282
if (my_strnicmp(value, "-CLEAR", 3))
283
{
284
for (tmp = command_history_head; command_history_head; tmp = command_history_head)
285
{
286
new_free(&tmp->stuff);
287
command_history_head = tmp->next;
288
new_free(&tmp);
289
}
290
hist_size = hist_count = 0;
291
command_history_pos = NULL;
292
command_history_tail = NULL;
293
command_history_head = NULL;
294
return;
295
}
296
if (isdigit((unsigned char)*value))
297
{
298
max = my_atol(value);
299
if (max > get_int_var(HISTORY_VAR))
300
max = get_int_var(HISTORY_VAR);
301
}
302
else
303
match = value;
304
}
305
else
306
max = get_int_var(HISTORY_VAR);
307
for (tmp = command_history_tail, cnt = 0; tmp && (match || (cnt < max));
308
tmp = tmp->prev, cnt++)
309
{
310
if (!match || (match && wild_match(match, tmp->stuff)))
311
put_it("%d: %s", tmp->number, tmp->stuff);
312
}
313
}
314
}
315
316
/*
317
* do_history: This finds the given history entry in either the history file,
318
* or the in memory history buffer (if no history file is given). It then
319
* returns the found entry as its function value, or null if the entry is not
320
* found for some reason. Note that this routine mallocs the string returned
321
*/
322
char *do_history (char *com, char *rest)
323
{
324
int hist_num;
325
char *ptr, *ret = NULL;
326
static char *last_com = NULL;
327
328
if (!com || !*com)
329
{
330
if (last_com)
331
com = last_com;
332
else
333
com = empty_string;
334
}
335
else
336
malloc_strcpy(&last_com, com);
337
338
if (!is_number(com))
339
{
340
if ((ptr = history_match(com)))
341
{
342
ret = m_strdup(ptr);
343
m_s3cat_s(&ret, space, rest);
344
return ret;
345
}
346
say("No Match");
347
}
348
else
349
{
350
hist_num = my_atol(com);
351
if (hist_num > 0)
352
{
353
for (tmp = command_history_head; tmp; tmp = tmp->next)
354
{
355
if (tmp->number == hist_num)
356
{
357
ret = m_strdup(tmp->stuff);
358
m_s3cat_s(&ret, space, rest);
359
return ret;
360
}
361
}
362
}
363
else
364
{
365
hist_num++;
366
for (tmp = command_history_head; tmp && hist_num < 0; )
367
tmp = tmp->next, hist_num++;
368
if (tmp)
369
{
370
ret = m_strdup(tmp->stuff);
371
m_s3cat_s(&ret, space, rest);
372
return (ret);
373
}
374
}
375
say("No such history entry: %d", hist_num);
376
}
377
return NULL;
378
}
379
380