Jspice3
glob.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  * Expand global characters.
10  */
11 
12 #include "spice.h"
13 #include "misc.h"
14 #include "cpdefs.h"
15 
16 #include <sys/types.h>
17 #ifdef HAVE_DIRENT_H
18 #include <dirent.h>
19 #ifndef direct
20 #define direct dirent
21 #endif
22 #else
23 #ifdef HAVE_SYS_DIR_H
24 #include <sys/dir.h>
25 #endif
26 #endif
27 #ifdef HAVE_GETPWUID
28 #include <pwd.h>
29 #endif
30 
31 #ifdef __STDC__
32 static wordlist *bracexpand(char*);
33 static wordlist *brac1(char*);
34 static wordlist *brac2(char*);
35 static wordlist *globexpand(char*);
36 static char *pcanon(char*);
37 static int sortcmp(char**,char**);
38 static char *tilde_expand(char*);
39 static bool noglobs(char*);
40 #else
41 static wordlist *bracexpand();
42 static wordlist *brac1();
43 static wordlist *brac2();
44 static wordlist *globexpand();
45 static char *pcanon();
46 static int sortcmp();
47 static char *tilde_expand();
48 static bool noglobs();
49 #endif
50 
51 char cp_comma = ',';
52 char cp_ocurl = '{';
53 char cp_ccurl = '}';
54 char cp_huh = '?';
55 char cp_star = '*';
56 char cp_obrac = '[';
57 char cp_cbrac = ']';
58 char cp_til = '~';
59 
60 /* For each word, go through two steps: expand the {}'s, and then do ?*[]
61  * globbing in them. Sort after the second phase but not the first...
62  */
63 
64 void
66 
67 wordlist **list;
68 {
69  wordlist *wl, *w, *nwl, *wlist;
70  char *s;
71 
72  /* Expand {a,b,c} */
73 
74  if (list == NULL) return;
75 
76  wlist = *list;
77 
78  for (wl = wlist; wl; wl = wl->wl_next) {
79  w = bracexpand(wl->wl_word);
80  if (!w) {
81  wl_free(wlist);
82  *list = NULL;
83  return;
84  }
85  nwl = wl_splice(wl, w);
86  if (wlist == wl)
87  wlist = w;
88  wl = nwl;
89  }
90 
91  /* Do tilde expansion. */
92 
93  for (wl = wlist; wl; wl = wl->wl_next)
94  if (*wl->wl_word == cp_til) {
95  s = cp_tildexpand(wl->wl_word);
96  tfree(wl->wl_word);
97  if (!s)
98  wl->wl_word = copy("");
99  else
100  wl->wl_word = s;
101  }
102 
103  /* Now, expand *?[] for each word. unset * and unalias * mean
104  * something special
105  */
106 
107  if ((cp_noglob == true) || eq(wlist->wl_word, "unset") ||
108  eq(wlist->wl_word, "unalias")) {
109  *list = wlist;
110  return;
111  }
112 
113  for (wl = wlist; wl; wl = wl->wl_next) {
114  if (noglobs(wl->wl_word))
115  continue;
116  w = globexpand(wl->wl_word);
117  if (w == NULL)
118  continue;
119  nwl = wl_splice(wl, w);
120  if (wlist == wl)
121  wlist = w;
122  wl = nwl;
123  }
124  *list = wlist;
125  return;
126 }
127 
128 
129 static wordlist *
130 bracexpand(string)
131 
132 char *string;
133 {
134  wordlist *wl, *w;
135  char *s;
136 
137  if (!string)
138  return (NULL);
139  wl = brac1(string);
140  if (!wl)
141  return (NULL);
142  for (w = wl; w; w = w->wl_next) {
143  s = w->wl_word;
144  w->wl_word = copy(s);
145  tfree(s);
146  }
147  return (wl);
148 }
149 
150 
151 /* Given a string, returns a wordlist of all the {} expansions. This is
152  * called recursively by cp_brac2(). All the words here will be of size
153  * BSIZE_SP, so it is a good idea to copy() and free() the old words.
154  */
155 
156 static wordlist *
157 brac1(string)
158 
159 char *string;
160 {
161  wordlist *words, *wl, *w, *nw, *nwl, *newwl;
162  char *s;
163  int nb;
164 
165  words = alloc(struct wordlist);
166  words->wl_word = tmalloc(BSIZE_SP);
167  for (s = string; *s; s++) {
168  if (*s == cp_ocurl) {
169  nwl = brac2(s);
170  nb = 0;
171  for (;;) {
172  if (*s == cp_ocurl)
173  nb++;
174  if (*s == cp_ccurl)
175  nb--;
176  if (*s == '\0') { /* { */
177  fprintf(cp_err, "Error: missing }.\n");
178  wl_free(words);
179  return (NULL);
180  }
181  if (nb == 0)
182  break;
183  s++;
184  }
185  /* Add nwl to the rest of the strings in words. */
186  newwl = NULL;
187  for (wl = words; wl; wl = wl->wl_next)
188  for (w = nwl; w; w = w->wl_next) {
189  nw = alloc(struct wordlist);
190  nw->wl_word = tmalloc(BSIZE_SP);
191  (void) strcpy(nw->wl_word, wl->wl_word);
192  (void) strcat(nw->wl_word, w->wl_word);
193  newwl = wl_append(newwl, nw);
194  }
195  wl_free(words);
196  words = newwl;
197  }
198  else
199  for (wl = words; wl; wl = wl->wl_next)
200  appendc(wl->wl_word, *s);
201  }
202  return (words);
203 }
204 
205 
206 /* Given a string starting with a {, return a wordlist of the expansions
207  * for the text until the matching }.
208  */
209 
210 static wordlist *
211 brac2(string)
212 
213 char *string;
214 {
215  wordlist *wlist = NULL, *nwl;
216  char buf[BSIZE_SP], *s;
217  int nb;
218  bool eflag = false;
219 
220  string++; /* Get past the first open brace... */
221  for (;;) {
222  (void) strcpy(buf, string);
223  nb = 0;
224  s = buf;
225  for (;;) {
226  if ((*s == cp_ccurl) && (nb == 0)) {
227  eflag = true;
228  break;
229  }
230  if ((*s == cp_comma) && (nb == 0))
231  break;
232  if (*s == cp_ocurl)
233  nb++;
234  if (*s == cp_ccurl)
235  nb--;
236  if (*s == '\0') { /* { */
237  fprintf(cp_err, "Error: missing }.\n");
238  wl_free(wlist);
239  return (NULL);
240  }
241  s++;
242  }
243  *s = '\0';
244  nwl = brac1(buf);
245  wlist = wl_append(wlist, nwl);
246  string += s - buf + 1;
247  if (eflag)
248  return (wlist);
249  }
250 }
251 
252 
253 /* Return a wordlist, with *?[] expanded and sorted. This is the idea: set
254  * up an array with possible matches, and go through each path component
255  * and search the appropriate directories for things that match, and add
256  * those that do to the array.
257  */
258 
259 static wordlist *
260 globexpand(string)
261 
262 char *string;
263 {
264  char *poss[MAXWORDS];
265  char buf[BSIZE_SP];
266  char *s;
267  char *point; /* Where we are at in the pathname. */
268  int i, j, level;
269  bool found;
270  wordlist *wlist = NULL, *wl, *lwl = NULL; /* Make lint shut up. */
271 #if defined(HAVE_DIRENT_H) || defined(HAVE_SYS_DIR_H)
272  DIR *wdir;
273  struct direct *de;
274 #endif
275 
276  bzero((char *) poss, MAXWORDS * sizeof (char *));
277  string = pcanon(string);
278  point = string;
279 
280  if (*point == DIR_TERM) {
281  point++;
282  poss[0] = copy(DIR_PATHSEP);
283  }
284  else if (point[0] == '.' && point[1] == '.' && point[2] == DIR_TERM) {
285  poss[0] = copy("..");
286  point += 3;
287  }
288 #ifdef MSDOS
289  else if (point[1] == ':') {
290  point += 2;
291  if (point[0] == DIR_TERM) {
292  point++;
293  poss[0] = copy("?:\\");
294  }
295  else
296  poss[0] = copy("?:.");
297  *poss[0] = *string;
298  }
299 #endif
300  else
301  poss[0] = copy(DIR_CWD);
302 
303  level = 0;
304 nextcomp:
305  level++;
306  (void) strcpy(buf, point);
307  s = strchr(buf, DIR_TERM);
308  if (s)
309  *s = '\0';
310 #if defined(HAVE_DIRENT_H) || defined(HAVE_SYS_DIR_H)
311  for (i = 0; i < MAXWORDS; i++) {
312  if (!poss[i] || (poss[i][0] == '\0'))
313  continue;
314  found = false;
315  wdir = opendir(poss[i]);
316  if (wdir == NULL) {
317  if (level > 1) {
318  tfree(poss[i]);
319  continue;
320  }
321  goto err;
322  }
323  while ((de = readdir(wdir)) != NULL)
324  if (cp_globmatch(buf, de->d_name)) {
325  found = true;
326  for (j = 0; j < MAXWORDS; j++)
327  if (!poss[j])
328  break;
329  if (j == MAXWORDS) {
330  fprintf(cp_err,
331  "Too many arguments.\n");
332  wl = NULL;
333  goto err1;
334  }
335  poss[j] = tmalloc(BSIZE_SP);
336  (void) strcpy(poss[j] + 1, poss[i]);
337  (void) strcat(poss[j] + 1, DIR_PATHSEP);
338  (void) strcat(poss[j] + 1, de->d_name);
339  }
340  tfree(poss[i]);
341  poss[i] = NULL;
342  (void) closedir(wdir);
343  if (!found) {
344  if (level > 1) {
345  continue;
346  }
347  goto err;
348  }
349  }
350  /* Hide the newly found words from the globbing process by making
351  * the first byte a '\0'.
352  */
353  for (i = 0; i < MAXWORDS; i++)
354  if (poss[i])
355  for (j = 0; poss[i][j] = poss[i][j+1]; j++);
356  if (strchr(point, DIR_TERM)) {
357  point = strchr(point, DIR_TERM) + 1;
358  goto nextcomp;
359  }
360 #endif
361 
362  /* Compact everything properly. */
363 
364  for (i = j = 0; i < MAXWORDS; i++) {
365  if (!poss[i]) continue;
366 
367  if (i != j) {
368  poss[j] = poss[i];
369  poss[i] = NULL;
370  }
371  j++;
372  }
373  if (j == 0)
374  goto err;
375 
376  /* Now, sort the stuff and make it into wordlists. */
377 
378  qsort((char *) poss, j, sizeof (char *),
379 #ifdef __STDC__
380  (int(*)(const void*,const void*))sortcmp);
381 #else
382  sortcmp);
383 #endif
384 
385  for (i = 0; i < j; i++) {
386 
387  if (wlist == NULL)
388  wlist = wl = alloc(wordlist);
389  else {
390  wl->wl_next = alloc(wordlist);
391  wl->wl_next->wl_prev = wl;
392  wl = wl->wl_next;
393  }
394  wl->wl_word = pcanon(poss[i]);
395  tfree(poss[i]);
396  }
397  tfree(string);
398  return (wlist);
399 
400 err:
401  if (cp_nonomatch) {
402  wl = alloc(wordlist);
403  wl->wl_word = copy(string);
404  }
405  else {
406  fprintf(cp_err, "%s: no match.\n", string);
407  wl = NULL;
408  }
409 
410 err1:
411  for (i = 0; i < MAXWORDS; i++)
412  if (poss[i])
413  tfree(poss[i]);
414  return (NULL);
415 }
416 
417 
418 /* Normalize filenames (get rid of extra ///, .///... etc.. ) */
419 
420 static char *
421 pcanon(string)
422 
423 char *string;
424 {
425  char *p, *s;
426 
427  s = p = tmalloc(strlen(string) + 1);
428 
429 bcomp:
430  if (!strncmp(string, DIR_CWD, sizeof(DIR_CWD) - 1)
431  && (*(string + 1) == DIR_TERM)) {
432  string += 2;
433  goto bcomp;
434  }
435 morew:
436  if (*string == DIR_TERM) {
437  *s++ = DIR_TERM;
438  while (*++string == DIR_TERM);
439  goto bcomp;
440  }
441  if (!*string) {
442  if (*(s - 1) == DIR_TERM)
443  s--;
444  *s = '\0';
445  return (p);
446  }
447  *s++ = *string++;
448  goto morew;
449 }
450 
451 
452 static int
453 sortcmp(s1, s2)
454 
455 char **s1, **s2;
456 {
457  char *a, *b;
458 
459  a = *s1;
460  b = *s2;
461  for (;;) {
462  if (*a > *b)
463  return (1);
464  if (*a < *b)
465  return (-1);
466  if (*a == '\0')
467  return (0);
468  a++;
469  b++;
470  }
471 }
472 
473 
474 /* Expand tildes. */
475 
476 char *
478 
479 char *string;
480 {
481  char *result;
482 
483  result = tilde_expand(string);
484 
485  if (!result) {
486  if (cp_nonomatch)
487  return (copy(string));
488  else
489  return (NULL);
490  }
491  return (result);
492 }
493 
494 
495 void
497 
498 char *buf;
499 {
500 #ifdef MSDOS
501  char *s, *t;
502  int bcnt = 0, ecnt = 0;
503 
504  s = t = buf;
505  while (*t != '\0') {
506  if (*t == '/' || *t == '\\') {
507  *s++ = '\\';
508  t++;
509  bcnt = 0;
510  ecnt = 0;
511  }
512  else if (*t == '.') {
513  *s++ = *t++;
514  ecnt = 1;
515  }
516  else if (!ecnt) {
517  if (bcnt++ < 8) *s++ = *t++;
518  else t++;
519  }
520  else {
521  if (ecnt++ < 4) *s++ = *t++;
522  else t++;
523  }
524  }
525  *s = '\0';
526 
527 #else
528  char *s;
529 
530  if (index(buf,'~')) {
531  s = cp_tildexpand(buf);
532  if (s) {
533  strcpy(buf,s);
534  txfree(s);
535  }
536  }
537 #endif
538 }
539 
540 
541 static char *
543 
544 char *string;
545 {
546 #ifdef HAVE_GETPWUID
547  struct passwd *pw;
548  char *tail;
549  char buf[BSIZE_SP];
550  char *k, c;
551 
552  if (!string)
553  return (NULL);
554 
555  while (*string && isspace(*string))
556  string++;
557 
558  if (*string != '~')
559  return copy(string);
560 
561  string += 1;
562 
563  if (!*string || *string == '/') {
564  pw = getpwuid(getuid());
565  *buf = 0;
566  }
567  else {
568  k = buf;
569  while ((c = *string) && c != '/')
570  *k++ = c, string++;
571  *k = 0;
572  pw = getpwnam(buf);
573  }
574 
575  if (pw) {
576  strcpy(buf, pw->pw_dir);
577  if (*string)
578  strcat(buf, string);
579  }
580  else
581  return (NULL);
582 
583  return (copy(buf));
584 
585 #else
586  return (copy(string));
587 #endif
588 }
589 
590 
591 /* Say whether the pattern p can match the string s. */
592 
593 bool
595 
596 char *p, *s;
597 {
598  char schar, pchar, bc, fc;
599  bool bchar, except;
600 
601  if ((*s == '.') && ((*p == cp_huh) || (*p == cp_star)))
602  return (false);
603 
604  for (;;) {
605  schar = strip(*s++);
606  pchar = *p++;
607  if (pchar == cp_star) {
608  if (*p == '\0')
609  return (true);
610  for (s--; *s != '\0'; s++)
611  if (cp_globmatch(p, s))
612  return (true);
613  return (false);
614  }
615  else if (pchar == cp_huh) {
616  if (schar == '\0')
617  return (false);
618  continue;
619  }
620  else if (pchar == cp_obrac) {
621  bchar = false;
622  if (*p == '^') {
623  except = true;
624  p++;
625  }
626  else
627  except = false;
628  fc = -1;
629  while (bc = *p++) {
630  if (bc == cp_cbrac) {
631  if ((bchar && !except) ||
632  (!bchar && except))
633  break;
634  else
635  return (false);
636  }
637  if (bc == '-') {
638  if (fc <= schar && schar <= *p++)
639  bchar = true;
640  }
641  else {
642  fc = bc;
643  if (fc == schar)
644  bchar = true;
645  }
646  }
647  if (bc == '\0') {
648  fprintf(cp_err, "Error: missing ].\n");
649  return (false);
650  }
651  continue;
652  }
653  else if (pchar == '\0') {
654  if (schar == '\0')
655  return (true);
656  else
657  return (false);
658  }
659  else {
660  if (strip(pchar) != schar)
661  return (false);
662  continue;
663  }
664  }
665 }
666 
667 
668 static bool
669 noglobs(string)
670 
671 char *string;
672 {
673  if (strchr(string, cp_star) || strchr(string, cp_huh) ||
674  strchr(string, cp_obrac))
675  return (false);
676  else
677  return (true);
678 }
static char buf[MAXPROMPT]
Definition: arg.c:18
#define BSIZE_SP
Definition: misc.h:19
#define eq(a, b)
Definition: misc.h:29
char cp_comma
Definition: glob.c:51
#define strip(c)
Definition: cpdefs.h:75
static wordlist * bracexpand()
char * strcpy()
static char * pcanon()
Definition: cddefs.h:119
void appendc()
FILE * p
Definition: proc2mod.c:48
char cp_ocurl
Definition: glob.c:52
Definition: cddefs.h:169
static wordlist * brac1()
char cp_cbrac
Definition: glob.c:57
Definition: library.c:18
Definition: cddefs.h:215
int bzero(char *ptr, int num)
Definition: string.c:357
#define alloc(type)
Definition: cdmacs.h:21
char * copy()
void wl_free()
FILE * cp_err
Definition: help.c:101
char * tmalloc()
#define tfree(x)
Definition: cdmacs.h:22
void txfree()
#define NULL
Definition: spdefs.h:121
wordlist * wl_splice()
void cp_pathfix(char *buf)
Definition: glob.c:496
static int sortcmp()
Definition: sced.h:120
wordlist * wl_append()
#define MAXWORDS
Definition: cpdefs.h:16
static double c
Definition: vectors.c:16
bool cp_globmatch(char *p, char *s)
Definition: glob.c:594
static wordlist * globexpand()
static char * tilde_expand()
Definition: cpstd.h:21
qsort()
Definition: string.c:375
char cp_huh
Definition: glob.c:54
char cp_star
Definition: glob.c:55
Definition: dir.c:53
char cp_til
Definition: glob.c:58
char * index(char *s, char c) const
Definition: string.c:294
struct wordlist * wl_next
Definition: cpstd.h:23
bool cp_nonomatch
Definition: variable.c:47
Definition: mfb.h:383
char * wl_word
Definition: cpstd.h:22
static wordlist * brac2()
char * cp_tildexpand(char *string)
Definition: glob.c:477
Definition: cddefs.h:192
char cp_ccurl
Definition: glob.c:53
char cp_obrac
Definition: glob.c:56
static bool noglobs()
void cp_doglob(wordlist **list)
Definition: glob.c:65
bool cp_noglob
Definition: variable.c:46