Jspice3
history.c
Go to the documentation of this file.
1 /***************************************************************************
2 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California. All rights reserved.
4 Authors: 1985 Wayne A. Christopher
5  1992 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 /*
9  * Do history substitutions.
10  */
11 
12 #include "spice.h"
13 #include "cpdefs.h"
14 #include "suffix.h"
15 
16 #ifdef __STDC__
17 static wordlist *dohsubst(char*);
18 static wordlist *dohmod(char**,wordlist*);
19 static wordlist *hpattern(char*);
20 static wordlist *hprefix(char*);
21 static wordlist *getevent(int);
22 static void freehist(int);
23 static char *dohs(char*,char*);
24 #else
25 static wordlist *dohsubst();
26 static wordlist *dohmod();
27 static wordlist *hpattern();
28 static wordlist *hprefix();
29 static wordlist *getevent();
30 static void freehist();
31 static char *dohs();
32 #endif
33 
35 int cp_maxhistlength = 1000;
36 char cp_hat = '^';
37 char cp_bang = '!';
39 
40 static int histlength = 0;
41 
42 /* First check for a ^ at the beginning
43  * of the line, and then search each word for !. Following this can be any
44  * of string, number, ?string, -number ; then there may be a word specifier,
45  * the same as csh, and then the : modifiers. For the :s modifier,
46  * the syntax is :sXoooXnnnX, where X is any character, and ooo and nnn are
47  * strings not containing X.
48  */
49 
50 void
52 
53 wordlist **list;
54 {
55  wordlist *nwl, *w, *n, *wlist;
56  char buf[BSIZE_SP], *s, *b;
57 
58  /* Replace ^old^new with !:s^old^new. */
59 
60  if (list == NULL)
61  return;
62  wlist = *list;
63  cp_didhsubst = false;
64  if (*wlist->wl_word == cp_hat) {
65  (void) sprintf(buf, "%c%c:s%s", cp_bang, cp_bang,
66  wlist->wl_word);
67  tfree(wlist->wl_word);
68  wlist->wl_word = copy(buf);
69  }
70  for (w = wlist; w; w = w->wl_next) {
71  b = w->wl_word;
72  for (s = b; *s; s++)
73  if (*s == cp_bang) {
74  cp_didhsubst = true;
75  n = dohsubst(s + 1);
76  if (!n) {
77  wl_free(wlist);
78  *list = NULL;
79  return;
80  }
81  if (b < s) {
82  (void) sprintf(buf, "%.*s%s", s - b, b,
83  n->wl_word);
84  tfree(n->wl_word);
85  n->wl_word = copy(buf);
86  }
87  nwl = wl_splice(w, n);
88  if (wlist == w)
89  wlist = n;
90  w = nwl;
91  break;
92  }
93  }
94  *list = wlist;
95  return;
96 }
97 
98 
99 /* Do a history substitution on one word. Figure out which event is
100  * being referenced, then do word selections and modifications, and
101  * then stick anything left over on the end of the last word.
102  */
103 
104 static wordlist *
105 dohsubst(string)
106 
107 char *string;
108 {
109  wordlist *wl, *nwl;
110  char buf[BSIZE_SP], *s, *r = NULL, *t;
111 
112  if (*string == cp_bang) {
113  if (cp_lastone) {
114  wl = cp_lastone->hi_wlist;
115  string++;
116  }
117  else {
118  fprintf(cp_err, "0: event not found.\n");
119  return (NULL);
120  }
121  }
122  else {
123  switch(*string) {
124 
125  case '-':
126  wl = getevent(cp_event - scannum(++string));
127  if (!wl)
128  return (NULL);
129  while (isdigit(*string))
130  string++;
131  break;
132 
133  case '?':
134  (void) strcpy(buf, string + 1);
135  if (s = strchr(buf, '?'))
136  *s = '\0';
137  wl = hpattern(buf);
138  if (!wl)
139  return (NULL);
140  if (s == NULL) /* No modifiers on this one. */
141  return (wl_copy(wl));
142  break;
143 
144  case '\0': /* Maybe this should be cp_event. */
145  wl = alloc(struct wordlist);
146  wl->wl_word = copy("!");
147  cp_didhsubst = false;
148  return (wl);
149 
150  default:
151  if (isdigit(*string)) {
152  wl = getevent(scannum(string));
153  if (!wl)
154  return (NULL);
155  while (isdigit(*string))
156  string++;
157  }
158  else {
159  (void) strcpy(buf, string);
160  for (s = ":^$*-%"; *s; s++) {
161  t = strchr(buf, *s);
162  if (t && ((t < r) || !r)) {
163  r = t;
164  string += r - buf;
165  }
166  }
167  if (r)
168  *r = '\0';
169  else
170  while (*string)
171  string++;
172  if ((buf[0] == '\0') && cp_lastone)
173  wl = cp_lastone->hi_wlist;
174  else
175  wl = hprefix(buf);
176  if (!wl)
177  return (NULL);
178  }
179  }
180  }
181  if (wl == NULL) { /* Shouldn't happen. */
182  fprintf(cp_err, "Event not found.\n");
183  return (NULL);
184  }
185  nwl = dohmod(&string, wl_copy(wl));
186  if (!nwl)
187  return (NULL);
188  if (*string) {
189  for (wl = nwl; wl->wl_next; wl = wl->wl_next)
190  ;
191  (void) sprintf(buf, "%s%s", wl->wl_word, string);
192  tfree(wl->wl_word);
193  wl->wl_word = copy(buf);
194  }
195  return (nwl);
196 }
197 
198 
199 static wordlist *
200 dohmod(string, wl)
201 
202 char **string;
203 wordlist *wl;
204 {
205  wordlist *w;
206  char *s;
207  char *r = NULL, *t;
208  int numwords, eventlo, eventhi, i;
209  bool globalsubst;
210 
211 anothermod:
212  numwords = wl_length(wl);
213  globalsubst = false;
214  eventlo = 0;
215  eventhi = numwords - 1;
216 
217  /* Now we know what wordlist we want. Take care of modifiers now. */
218  r = NULL;
219  for (s = ":^$*-%"; *s; s++) {
220  t = strchr(*string, *s);
221  if (t && ((t < r) || (r == NULL)))
222  r = t;
223  }
224  if (!r) /* No more modifiers. */
225  return (wl);
226 
227  *string = r;
228  if (**string == ':')
229  (*string)++;
230 
231  switch(**string) {
232  case '$': /* Last word. */
233  eventhi = eventlo = numwords - 1;
234  break;
235  case '*': /* Words 1 through $ */
236  if (numwords == 1)
237  return (NULL);
238  eventlo = 1;
239  eventhi = numwords - 1;
240  break;
241  case '-': /* Words 0 through ... */
242  eventlo = 0;
243  if (*(*string + 1))
244  eventhi = scannum(*string + 1);
245  else
246  eventhi = numwords - 1;
247  if (eventhi > numwords - 1)
248  eventhi = numwords - 1;
249  break;
250  case 'p': /* Print the command and don't execute it.
251  * This doesn't work quite like csh.
252  */
253  wl_print(wl, cp_out);
254  (void) putc('\n', cp_out);
255  return (NULL);
256  case 's': /* Do a substitution. */
257  for (w = wl; w; w = w->wl_next) {
258  s = dohs(*string + 1, w->wl_word);
259  if (s) {
260  tfree(w->wl_word);
261  w->wl_word = s;
262  if (globalsubst == false) {
263  while (**string)
264  (*string)++;
265  break;
266  }
267  }
268  }
269  /* In case globalsubst is true... */
270  while (**string)
271  (*string)++;
272  break;
273  default:
274  if (!isdigit(**string)) {
275  fprintf(cp_err, "Error: %s: bad modifier.\n",
276  *string);
277  return (NULL);
278  }
279  i = scannum(*string);
280  if (i > eventhi) {
281  fprintf(cp_err, "Error: bad event number %d\n",
282  i);
283  return (NULL);
284  }
285  eventhi = eventlo = i;
286  while (isdigit(**string))
287  (*string)++;
288  if (**string == '*')
289  eventhi = numwords - 1;
290  if (**string == '-')
291  if (!isdigit(*(*string + 1)))
292  eventhi = numwords - 1;
293  else {
294  eventhi = scannum(++*string);
295  while (isdigit(**string))
296  (*string)++;
297  }
298  }
299  /* Now change the word list accordingly and make another pass
300  * if there is more of the substitute left.
301  */
302 
303  wl = wl_range(wl, eventlo, eventhi);
304  numwords = wl_length(wl);
305  if (**string && *++*string)
306  goto anothermod;
307  return (wl);
308 }
309 
310 
311 /* Look for an event with a pattern in it... */
312 
313 static wordlist *
315 
316 char *buf;
317 {
318  struct histent *hi;
319  wordlist *wl;
320 
321  if (*buf == '\0') {
322  fprintf(cp_err, "Bad pattern specification.\n");
323  return (NULL);
324  }
325  for (hi = cp_lastone; hi; hi = hi->hi_prev)
326  for (wl = hi->hi_wlist; wl; wl = wl->wl_next)
327  if (substring(buf, wl->wl_word))
328  return (hi->hi_wlist);
329  fprintf(cp_err, "%s: event not found.\n", buf);
330  return (NULL);
331 }
332 
333 
334 static wordlist *
336 
337 char *buf;
338 {
339  struct histent *hi;
340 
341  if (*buf == '\0') {
342  fprintf(cp_err, "Bad pattern specification.\n");
343  return (NULL);
344  }
345  for (hi = cp_lastone; hi; hi = hi->hi_prev)
346  if (hi->hi_wlist && prefix(buf, hi->hi_wlist->wl_word))
347  return (hi->hi_wlist);
348  fprintf(cp_err, "%s: event not found.\n", buf);
349  return (NULL);
350 }
351 
352 
353 /* Add a wordlist to the history list. (Done after the first parse.) Note
354  * that if event numbers are given in a random order that's how they'll
355  * show up in the history list.
356  */
357 
358 void
359 cp_addhistent(event, wlist)
360 
361 int event;
362 wordlist *wlist;
363 {
364  if (cp_lastone && !cp_lastone->hi_wlist)
365  fprintf(cp_err, "Internal error: bad history list\n");
366  if (cp_lastone == NULL) {
367  cp_lastone = alloc(struct histent);
368  }
369  else {
370  cp_lastone->hi_next = alloc(struct histent);
371  cp_lastone->hi_next->hi_prev = cp_lastone;
372  cp_lastone = cp_lastone->hi_next;
373  }
374  cp_lastone->hi_event = event;
375  cp_lastone->hi_wlist = wl_copy(wlist);
377  histlength++;
378  return;
379 }
380 
381 
382 /* Get a copy of the wordlist associated with an event. Error if out
383  * of range.
384  */
385 
386 static wordlist *
388 
389 int num;
390 {
391  struct histent *hi;
392 
393  for (hi = cp_lastone; hi; hi = hi->hi_prev)
394  if (hi->hi_event == num)
395  break;
396  if (hi == NULL) {
397  fprintf(cp_err, "%d: event not found.\n", num);
398  return (NULL);
399  }
400  return (hi->hi_wlist);
401 }
402 
403 
404 /* Print out history between eventhi and eventlo.
405  * This doesn't remember quoting, so 'hodedo' prints as hodedo.
406  */
407 
408 void
409 cp_hprint(eventhi, eventlo, rev)
410 
411 int eventhi, eventlo;
412 bool rev;
413 {
414  struct histent *hi;
415 
416  if (rev) {
417  for (hi = cp_lastone; hi; hi = hi->hi_prev) {
418  if ((hi->hi_event <= eventhi) &&
419  (hi->hi_event >= eventlo) &&
420  hi->hi_wlist) {
421  out_printf("%d\t", hi->hi_event);
422  out_wlprint(hi->hi_wlist);
423  out_send("\n");
424  }
425  }
426  }
427  else if (cp_lastone) {
428  for (hi = cp_lastone; hi->hi_prev; hi = hi->hi_prev)
429  ;
430  for (; hi; hi = hi->hi_next) {
431  if ((hi->hi_event <= eventhi) &&
432  (hi->hi_event >= eventlo) &&
433  hi->hi_wlist) {
434  out_printf("%d\t", hi->hi_event);
435  out_wlprint(hi->hi_wlist);
436  out_send("\n");
437  }
438  }
439  }
440  return;
441 }
442 
443 
444 /* This just gets rid of the first num entries on the history list, and
445  * decrements histlength.
446  */
447 
448 static void
450 
451 int num;
452 {
453  struct histent *hi, *ht;
454 
455  if (num < 1 || !cp_lastone)
456  return;
457 
458  histlength -= num;
459  if (histlength <= 0) {
460  histlength = 0;
461  for (ht = cp_lastone; ht; ht = hi) {
462  hi = ht->hi_prev;
463  wl_free(ht->hi_wlist);
464  txfree((char*)ht);
465  }
466  cp_lastone = NULL;
467  return;
468  }
469 
470  num = histlength;
471  hi = cp_lastone;
472  while (num-- && hi->hi_prev)
473  hi = hi->hi_prev;
474  if (hi->hi_prev) {
475  ht = hi->hi_prev;
476  hi->hi_prev = NULL;
477  for (; ht; ht = hi) {
478  hi = ht->hi_prev;
479  wl_free(ht->hi_wlist);
480  txfree((char*)ht);
481  }
482  }
483  else {
484  fprintf(cp_err, "Internal error: history list mangled\n");
485  }
486 }
487 
488 
489 /* Do a :s substitution. */
490 
491 static char *
492 dohs(patrn, str)
493 
494 char *patrn, *str;
495 {
496  char schar, *s, *p, buf[BSIZE_SP], *pat, pbuf[BSIZE_SP];
497  int i = 0, plen;
498  bool ok = false;
499 
500  if (patrn == NULL)
501  goto err;
502  strcpy(pbuf,patrn);
503  pat = pbuf;
504  schar = *pat++;
505  s = strchr(pat, schar);
506  if (s == NULL) {
507  fprintf(cp_err, "Bad substitute.\n");
508  goto err;
509  }
510  *s++ = '\0';
511  p = strchr(s, schar);
512  if (p)
513  *p = '\0';
514  plen = strlen(pat) - 1;
515  for (i = 0; *str; str++) {
516  if ((*str == *pat) && prefix(pat, str) && (ok == false)) {
517  for (p = s; *p; p++)
518  buf[i++] = *p;
519  str += plen;
520  ok = true;
521  }
522  else
523  buf[i++] = *str;
524  }
525  buf[i] = '\0';
526  if (ok)
527  return (copy(buf));
528 err:
529  return (NULL);
530 }
531 
532 
533 /* The "history" command. history [-r] [number] */
534 
535 void
537 
538 wordlist *wl;
539 {
540  bool rev = false;
541 
542  if (wl && eq(wl->wl_word, "-r")) {
543  wl = wl->wl_next;
544  rev = true;
545  }
546  if (wl == NULL)
547  cp_hprint(cp_event - 1, cp_event - histlength, rev);
548  else
549  cp_hprint(cp_event - 1, cp_event - 1 - atoi(wl->wl_word), rev);
550  return;
551 }
552 
static char buf[MAXPROMPT]
Definition: arg.c:18
#define BSIZE_SP
Definition: misc.h:19
void wl_print()
#define eq(a, b)
Definition: misc.h:29
bool cp_didhsubst
Definition: history.c:38
wordlist * wl_range()
void out_wlprint()
wordlist * hi_wlist
Definition: cpdefs.h:42
int wl_length()
int cp_event
Definition: lexical.c:49
struct histent * hi_prev
Definition: cpdefs.h:44
#define prefix(x, y)
Definition: readhelp.c:39
void out_printf()
char * strcpy()
Definition: cddefs.h:119
static wordlist * hpattern()
char cp_bang
Definition: history.c:37
void cp_hprint(int eventhi, int eventlo, bool rev)
Definition: history.c:409
int scannum()
FILE * p
Definition: proc2mod.c:48
void com_history(wordlist *wl)
Definition: history.c:536
Definition: cddefs.h:169
void cp_addhistent(int event, wordlist *wlist)
Definition: history.c:359
Definition: library.c:18
#define alloc(type)
Definition: cdmacs.h:21
static wordlist * getevent()
void cp_histsubst(wordlist **list)
Definition: history.c:51
char * copy()
struct histent * cp_lastone
Definition: history.c:34
void wl_free()
FILE * cp_err
Definition: help.c:101
int substring()
#define tfree(x)
Definition: cdmacs.h:22
Definition: cpdefs.h:40
void txfree()
#define NULL
Definition: spdefs.h:121
wordlist * wl_splice()
FILE * cp_out
Definition: help.c:101
static int histlength
Definition: history.c:40
static char * dohs()
struct wl * wl_next
Definition: library.c:20
Definition: cpstd.h:21
int cp_maxhistlength
Definition: history.c:35
static void freehist()
Definition: dir.c:53
Definition: cddefs.h:162
void out_send()
struct wordlist * wl_next
Definition: cpstd.h:23
static wordlist * dohsubst()
Definition: mfb.h:383
char cp_hat
Definition: history.c:36
int hi_event
Definition: cpdefs.h:41
char * wl_word
Definition: cpstd.h:22
struct histent * hi_next
Definition: cpdefs.h:43
Definition: cddefs.h:192
static wordlist * hprefix()
static wordlist * dohmod()
wordlist * wl_copy()