glob.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <regexp.h>
  12. #include <String.h>
  13. #include "glob.h"
  14. /*
  15. * I wrote this glob so that there would be no limit
  16. * on element or path size. The one in rc is probably
  17. * better, certainly faster. - presotto
  18. */
  19. static Glob*
  20. globnew(void)
  21. {
  22. Glob *g;
  23. g = mallocz(sizeof(*g), 1);
  24. if(g == nil)
  25. sysfatal("globnew: %r");
  26. return g;
  27. }
  28. static void
  29. globfree1(Glob *g)
  30. {
  31. s_free(g->glob);
  32. free(g);
  33. }
  34. static void
  35. globfree(Glob *g)
  36. {
  37. Glob *next;
  38. for(; g != nil; g = next){
  39. next = g->next;
  40. globfree1(g);
  41. }
  42. }
  43. static Globlist*
  44. globlistnew(char *x)
  45. {
  46. Globlist *gl;
  47. gl = mallocz(sizeof *gl, 1);
  48. if(gl == nil)
  49. sysfatal("globlistnew: %r");
  50. gl->first = globnew();
  51. gl->first->glob = s_copy(x);
  52. gl->l = &gl->first->next;
  53. return gl;
  54. }
  55. void
  56. globlistfree(Globlist *gl)
  57. {
  58. if(gl == nil)
  59. return;
  60. globfree(gl->first);
  61. free(gl);
  62. }
  63. void
  64. globadd(Globlist *gl, char *dir, char *file)
  65. {
  66. Glob *g;
  67. g = globnew();
  68. g->glob = s_copy(dir);
  69. if(strcmp(dir, "/") != 0 && *dir != 0)
  70. s_append(g->glob, "/");
  71. s_append(g->glob, file);
  72. *(gl->l) = g;
  73. gl->l = &(g->next);
  74. }
  75. static void
  76. globdir(Globlist *gl, char *dir, Reprog *re)
  77. {
  78. Dir *d;
  79. int i, n, fd;
  80. if(*dir == 0)
  81. fd = open(".", OREAD);
  82. else
  83. fd = open(dir, OREAD);
  84. if(fd < 0)
  85. return;
  86. n = dirreadall(fd, &d);
  87. if(n == 0)
  88. return;
  89. close(fd);
  90. for(i = 0; i < n; i++)
  91. if(regexec(re, d[i].name, nil, 0))
  92. globadd(gl, dir, d[i].name);
  93. free(d);
  94. }
  95. static void
  96. globdot(Globlist *gl, char *dir)
  97. {
  98. Dir *d;
  99. if(*dir == 0){
  100. globadd(gl, "", ".");
  101. return;
  102. }
  103. d = dirstat(dir);
  104. if(d == nil)
  105. return;
  106. if(d->qid.type & QTDIR)
  107. globadd(gl, dir, ".");
  108. free(d);
  109. }
  110. static void
  111. globnext(Globlist *gl, char *pattern)
  112. {
  113. String *np;
  114. Glob *g, *inlist;
  115. Reprog *re;
  116. int c;
  117. /* nothing left */
  118. if(*pattern == 0)
  119. return;
  120. inlist = gl->first;
  121. gl->first = nil;
  122. gl->l = &gl->first;
  123. /* pick off next pattern and turn into a reg exp */
  124. np = s_new();
  125. s_putc(np, '^');
  126. for(; c = *pattern; pattern++){
  127. if(c == '/'){
  128. pattern++;
  129. break;
  130. }
  131. switch(c){
  132. case '|':
  133. case '+':
  134. case '.':
  135. case '^':
  136. case '$':
  137. case '(':
  138. case ')':
  139. s_putc(np, '\\');
  140. s_putc(np, c);
  141. break;
  142. case '?':
  143. s_putc(np, '.');
  144. break;
  145. case '*':
  146. s_putc(np, '.');
  147. s_putc(np, '*');
  148. break;
  149. default:
  150. s_putc(np, c);
  151. break;
  152. }
  153. }
  154. s_putc(np, '$');
  155. s_terminate(np);
  156. if(strcmp(s_to_c(np), "^\\.$") == 0){
  157. /* anything that's a directory works */
  158. for(g = inlist; g != nil; g = g->next)
  159. globdot(gl, s_to_c(g->glob));
  160. } else {
  161. re = regcomp(s_to_c(np));
  162. /* run input list as directories */
  163. for(g = inlist; g != nil; g = g->next)
  164. globdir(gl, s_to_c(g->glob), re);
  165. free(re);
  166. }
  167. s_free(np);
  168. globfree(inlist);
  169. if(gl->first != nil)
  170. globnext(gl, pattern);
  171. }
  172. char *
  173. globiter(Globlist *gl)
  174. {
  175. Glob *g;
  176. char *s;
  177. if(gl->first == nil)
  178. return nil;
  179. g = gl->first;
  180. gl->first = g->next;
  181. if(gl->first == nil)
  182. gl->l = &gl->first;
  183. s = strdup(s_to_c(g->glob));
  184. if(s == nil)
  185. sysfatal("globiter: %r");
  186. globfree1(g);
  187. return s;
  188. }
  189. Globlist*
  190. glob(char *pattern)
  191. {
  192. Globlist *gl;
  193. if(pattern == nil || *pattern == 0)
  194. return nil;
  195. if(*pattern == '/'){
  196. pattern++;
  197. gl = globlistnew("/");
  198. } else
  199. gl = globlistnew("");
  200. globnext(gl, pattern);
  201. return gl;
  202. }