varsub.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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 "mk.h"
  10. static Word *subsub(Word*, char*, char*);
  11. static Word *expandvar(char**);
  12. static Bufblock *varname(char**);
  13. static Word *extractpat(char*, char**, char*,
  14. char*);
  15. static int submatch(char*, Word*, Word*, int*,
  16. char**);
  17. static Word *varmatch(char *);
  18. Word *
  19. varsub(char **s)
  20. {
  21. Bufblock *b;
  22. Word *w;
  23. if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/
  24. return expandvar(s);
  25. b = varname(s);
  26. if(b == 0)
  27. return 0;
  28. w = varmatch(b->start);
  29. freebuf(b);
  30. return w;
  31. }
  32. /*
  33. * extract a variable name
  34. */
  35. static Bufblock*
  36. varname(char **s)
  37. {
  38. Bufblock *b;
  39. char *cp;
  40. Rune r;
  41. int n;
  42. b = newbuf();
  43. cp = *s;
  44. for(;;){
  45. n = chartorune(&r, cp);
  46. if (!WORDCHR(r))
  47. break;
  48. rinsert(b, r);
  49. cp += n;
  50. }
  51. if (b->current == b->start){
  52. SYNERR(-1);
  53. fprint(2, "missing variable name <%s>\n", *s);
  54. freebuf(b);
  55. return 0;
  56. }
  57. *s = cp;
  58. insert(b, 0);
  59. return b;
  60. }
  61. static Word*
  62. varmatch(char *name)
  63. {
  64. Word *w;
  65. Symtab *sym;
  66. sym = symlook(name, S_VAR, 0);
  67. if(sym){
  68. /* check for at least one non-NULL value */
  69. for (w = sym->u.ptr; w; w = w->next)
  70. if(w->s && *w->s)
  71. return wdup(w);
  72. }
  73. return 0;
  74. }
  75. static Word*
  76. expandvar(char **s)
  77. {
  78. Word *w;
  79. Bufblock *buf;
  80. Symtab *sym;
  81. char *cp, *begin, *end;
  82. begin = *s;
  83. (*s)++; /* skip the '{' */
  84. buf = varname(s);
  85. if (buf == 0)
  86. return 0;
  87. cp = *s;
  88. if (*cp == '}') { /* ${name} variant*/
  89. (*s)++; /* skip the '}' */
  90. w = varmatch(buf->start);
  91. freebuf(buf);
  92. return w;
  93. }
  94. if (*cp != ':') {
  95. SYNERR(-1);
  96. fprint(2, "bad variable name <%s>\n", buf->start);
  97. freebuf(buf);
  98. return 0;
  99. }
  100. cp++;
  101. end = charin(cp , "}");
  102. if(end == 0){
  103. SYNERR(-1);
  104. fprint(2, "missing '}': %s\n", begin);
  105. Exit();
  106. }
  107. *end = 0;
  108. *s = end+1;
  109. sym = symlook(buf->start, S_VAR, 0);
  110. if(sym == 0 || sym->u.value == 0)
  111. w = newword(buf->start);
  112. else
  113. w = subsub(sym->u.ptr, cp, end);
  114. freebuf(buf);
  115. return w;
  116. }
  117. static Word*
  118. extractpat(char *s, char **r, char *term, char *end)
  119. {
  120. int save;
  121. char *cp;
  122. Word *w;
  123. cp = charin(s, term);
  124. if(cp){
  125. *r = cp;
  126. if(cp == s)
  127. return 0;
  128. save = *cp;
  129. *cp = 0;
  130. w = stow(s);
  131. *cp = save;
  132. } else {
  133. *r = end;
  134. w = stow(s);
  135. }
  136. return w;
  137. }
  138. static Word*
  139. subsub(Word *v, char *s, char *end)
  140. {
  141. int nmid;
  142. Word *head, *tail, *w, *h;
  143. Word *a, *b, *c, *d;
  144. Bufblock *buf;
  145. char *cp, *enda;
  146. a = extractpat(s, &cp, "=%&", end);
  147. b = c = d = 0;
  148. if(PERCENT(*cp))
  149. b = extractpat(cp+1, &cp, "=", end);
  150. if(*cp == '=')
  151. c = extractpat(cp+1, &cp, "&%", end);
  152. if(PERCENT(*cp))
  153. d = stow(cp+1);
  154. else if(*cp)
  155. d = stow(cp);
  156. head = tail = 0;
  157. buf = newbuf();
  158. for(; v; v = v->next){
  159. h = w = 0;
  160. if(submatch(v->s, a, b, &nmid, &enda)){
  161. /* enda points to end of A match in source;
  162. * nmid = number of chars between end of A and start of B
  163. */
  164. if(c){
  165. h = w = wdup(c);
  166. while(w->next)
  167. w = w->next;
  168. }
  169. if(PERCENT(*cp) && nmid > 0){
  170. if(w){
  171. bufcpy(buf, w->s, strlen(w->s));
  172. bufcpy(buf, enda, nmid);
  173. insert(buf, 0);
  174. free(w->s);
  175. w->s = strdup(buf->start);
  176. } else {
  177. bufcpy(buf, enda, nmid);
  178. insert(buf, 0);
  179. h = w = newword(buf->start);
  180. }
  181. buf->current = buf->start;
  182. }
  183. if(d && *d->s){
  184. if(w){
  185. bufcpy(buf, w->s, strlen(w->s));
  186. bufcpy(buf, d->s, strlen(d->s));
  187. insert(buf, 0);
  188. free(w->s);
  189. w->s = strdup(buf->start);
  190. w->next = wdup(d->next);
  191. while(w->next)
  192. w = w->next;
  193. buf->current = buf->start;
  194. } else
  195. h = w = wdup(d);
  196. }
  197. }
  198. if(w == 0)
  199. h = w = newword(v->s);
  200. if(head == 0)
  201. head = h;
  202. else
  203. tail->next = h;
  204. tail = w;
  205. }
  206. freebuf(buf);
  207. delword(a);
  208. delword(b);
  209. delword(c);
  210. delword(d);
  211. return head;
  212. }
  213. static int
  214. submatch(char *s, Word *a, Word *b, int *nmid, char **enda)
  215. {
  216. Word *w;
  217. int n;
  218. char *end;
  219. n = 0;
  220. for(w = a; w; w = w->next){
  221. n = strlen(w->s);
  222. if(strncmp(s, w->s, n) == 0)
  223. break;
  224. }
  225. if(a && w == 0) /* a == NULL matches everything*/
  226. return 0;
  227. *enda = s+n; /* pointer to end a A part match */
  228. *nmid = strlen(s)-n; /* size of remainder of source */
  229. end = *enda+*nmid;
  230. for(w = b; w; w = w->next){
  231. n = strlen(w->s);
  232. if(strcmp(w->s, end-n) == 0){
  233. *nmid -= n;
  234. break;
  235. }
  236. }
  237. if(b && w == 0) /* b == NULL matches everything */
  238. return 0;
  239. return 1;
  240. }