glob.c 2.9 KB

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