varsub.c 4.3 KB

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