xref: /plan9-contrib/sys/src/ape/cmd/make/misc.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include "defs.h"
2 
3 static int	hasslash(char *);
4 static int	haspercent(char *);
5 static void	rehash(void);
6 
7 /* simple linear hash.  hash function is sum of
8    characters mod hash table size.
9 */
10 static int
11 hashloc(char *s)
12 {
13 int i;
14 int hashval;
15 char *t;
16 
17 hashval = 0;
18 
19 for(t=s; *t!='\0' ; ++t)
20 	hashval += *t;
21 
22 hashval %= hashsize;
23 
24 for(i=hashval;
25 	hashtab[i]!=0 && !equal(s,hashtab[i]->namep);
26 	i = i >= hashsize-1 ? 0 : i+1) ;
27 
28 return i;
29 }
30 
31 
32 nameblkp
33 srchname(char *s)
34 {
35 return  hashtab[hashloc(s)] ;
36 }
37 
38 
39 
40 nameblkp
41 makename(char *s)
42 {
43 nameblkp p;
44 
45 if(nhashed > hashthresh)
46 	rehash();
47 
48 ++nhashed;
49 hashtab[hashloc(s)] = p = ALLOC(nameblock);
50 p->nxtnameblock = firstname;
51 p->namep = copys(s);	/* make a fresh copy of the string s */
52 /* p->linep = 0; p->done = 0; p->septype = 0; p->modtime = 0; */
53 
54 firstname = p;
55 if(mainname==NULL && !haspercent(s) && (*s!='.' || hasslash(s)) )
56 	mainname = p;
57 
58 return p;
59 }
60 
61 
62 static int
63 hasslash(char *s)
64 {
65 for( ; *s ; ++s)
66 	if(*s == '/')
67 		return YES;
68 return NO;
69 }
70 
71 static int
72 haspercent(char *s)
73 {
74 for( ; *s ; ++s)
75 	if(*s == '%')
76 		return YES;
77 return NO;
78 }
79 
80 int
81 hasparen(char *s)
82 {
83 for( ; *s ; ++s)
84 	if(*s == '(')
85 		return YES;
86 return NO;
87 }
88 
89 static void
90 rehash(void)
91 {
92 nameblkp *ohash;
93 nameblkp p, *hp, *endohash;
94 hp = ohash = hashtab;
95 endohash = hashtab + hashsize;
96 
97 newhash(2*hashsize);
98 
99 while( hp<endohash )
100 	if(p = *hp++)
101 		hashtab[hashloc(p->namep)] = p;
102 
103 free( (char *) ohash);
104 }
105 
106 
107 void
108 newhash(int newsize)
109 {
110 hashsize = newsize;
111 hashtab = (nameblkp *) ckalloc(hashsize * sizeof(nameblkp));
112 hashthresh = (2*hashsize)/3;
113 }
114 
115 
116 
117 nameblkp chkname(char *s)
118 {
119 nameblkp p;
120 time_t k;
121 /*TEMP NEW */
122 if(hasparen(s))
123 	{
124 	k = lookarch(s);
125 /*TEMP	fprintf(stderr, "chkname(%s): look=%d\n", s, k); */
126 	if(k == 0)
127 		return NULL;
128 	}
129 if(p = srchname(s))
130 	return p;
131 dirsrch(s);
132 return srchname(s);
133 }
134 
135 
136 
137 char *
138 copys(char *s)
139 {
140 char *t;
141 
142 if( (t = malloc( strlen(s)+1 ) ) == NULL)
143 	fatal("out of memory");
144 strcpy(t, s);
145 return t;
146 }
147 
148 
149 
150 char *
151 concat(char *a, char *b, char *c)   /* c = concatenation of a and b */
152 {
153 char *t;
154 t = c;
155 
156 while(*t = *a++) t++;
157 while(*t++ = *b++);
158 return c;
159 }
160 
161 
162 int
163 suffix(char *a, char *b, char *p)  /* is b the suffix of a?  if so, set p = prefix */
164 {
165 char *a0,*b0;
166 a0 = a;
167 b0 = b;
168 
169 while(*a++);
170 while(*b++);
171 
172 if( (a-a0) < (b-b0) ) return 0;
173 
174 while(b>b0)
175 	if(*--a != *--b) return 0;
176 
177 while(a0<a) *p++ = *a0++;
178 *p = '\0';
179 
180 return 1;
181 }
182 
183 int *
184 ckalloc(int n)
185 {
186 int *p;
187 
188 if( p = (int *) calloc(1,n) )
189 	return p;
190 
191 fatal("out of memory");
192 /* NOTREACHED */
193 }
194 
195 /* copy string a into b, substituting for arguments */
196 char *
197 subst(char *a, char *b)
198 {
199 static depth	= 0;
200 char *s;
201 char vname[100];
202 struct varblock *vbp;
203 char closer;
204 
205 if(++depth > 100)
206 	fatal("infinitely recursive macro?");
207 if(a)  while(*a)
208 	{
209 	if(*a!='$' || a[1]=='\0' || *++a=='$')
210 		/* if a non-macro character copy it.  if $$ or $\0, copy $ */
211 		*b++ = *a++;
212 	else	{
213 		s = vname;
214 		if( *a=='(' || *a=='{' )
215 			{
216 			closer = ( *a=='(' ? ')' : '}');
217 			++a;
218 			while(*a == ' ') ++a;
219 			while(*a!=' ' && *a!=closer && *a!='\0') *s++ = *a++;
220 			while(*a!=closer && *a!='\0') ++a;
221 			if(*a == closer) ++a;
222 			}
223 		else	*s++ = *a++;
224 
225 		*s = '\0';
226 		if( (vbp = varptr(vname)) ->varval != 0)
227 			{
228 			b = subst(vbp->varval, b);
229 			vbp->used = YES;
230 			}
231 		}
232 	}
233 
234 *b = '\0';
235 --depth;
236 return b;
237 }
238 
239 void
240 setvar(char *v, char *s, int dyn)
241 {
242 struct varblock *p;
243 
244 p = varptr(v);
245 if( ! p->noreset )
246 	{
247 	p->varval = s;
248 	p->noreset = inarglist;
249 	if(p->used && !dyn)
250 		fprintf(stderr, "Warning: %s changed after being used\n",v);
251 	if(p->export)
252 		{
253 		/* change string pointed to by environment to new v=s */
254 		char *t;
255 		int lenv;
256 		lenv = strlen(v);
257 		*(p->export) = t = (char *) ckalloc(lenv + strlen(s) + 2);
258 		strcpy(t,v);
259 		t[lenv] = '=';
260 		strcpy(t+lenv+1, s);
261 		}
262 	else
263 		p->export = envpp;
264 	}
265 }
266 
267 
268 /* for setting Bradford's *D and *F family of macros whens setting * etc */
269 void
270 set3var(char *macro, char *value)
271 {
272 char *s;
273 char macjunk[8], *lastslash, *dirpart, *filepart;
274 
275 setvar(macro, value, YES);
276 if(value == CHNULL)
277 	dirpart = filepart = CHNULL;
278 else
279 	{
280 	lastslash = CHNULL;
281 	for(s = value; *s; ++s)
282 		if(*s == '/')
283 			lastslash = s;
284 	if(lastslash)
285 		{
286 		dirpart = copys(value);
287 		filepart = dirpart + (lastslash-value);
288 		filepart[-1] = '\0';
289 		}
290 	else
291 		{
292 		dirpart = "";
293 		filepart = value;
294 		}
295 	}
296 setvar(concat(macro, "D", macjunk), dirpart, YES);
297 setvar(concat(macro, "F", macjunk), filepart, YES);
298 }
299 
300 
301 int
302 eqsign(char *a)   /*look for arguments with equal signs but not colons */
303 {
304 char *s, *t;
305 char c;
306 
307 while(*a == ' ') ++a;
308 for(s=a  ;   *s!='\0' && *s!=':'  ; ++s)
309 	if(*s == '=')
310 		{
311 		for(t = a ; *t!='=' && *t!=' ' && *t!='\t' ;  ++t );
312 		c = *t;
313 		*t = '\0';
314 
315 		for(++s; *s==' ' || *s=='\t' ; ++s);
316 		setvar(a, copys(s), NO);
317 		*t = c;
318 		return YES;
319 		}
320 
321 return NO;
322 }
323 
324 struct varblock *
325 varptr(char *v)
326 {
327 struct varblock *vp;
328 
329 /* for compatibility, $(TGS) = $^ */
330 if(equal(v, "TGS") )
331 	v = "^";
332 for(vp = firstvar; vp ; vp = vp->nxtvarblock)
333 	if(equal(v , vp->varname))
334 		return vp;
335 
336 vp = ALLOC(varblock);
337 vp->nxtvarblock = firstvar;
338 firstvar = vp;
339 vp->varname = copys(v);
340 vp->varval = 0;
341 return vp;
342 }
343 
344 int
345 dynmacro(char *line)
346 {
347 char *s;
348 char endc, *endp;
349 if(!isalpha(line[0]))
350 	return NO;
351 for(s=line+1 ; *s && (isalpha(*s) | isdigit(*s)) ; ++s)
352 	;
353 endp = s;
354 while( isspace(*s) )
355 	++s;
356 if(s[0]!=':' || s[1]!='=')
357 	return NO;
358 
359 endc = *endp;
360 *endp = '\0';
361 setvar(line, copys(s+2), YES);
362 *endp = endc;
363 
364 return YES;
365 }
366 
367 
368 void
369 fatal1(char *s, char *t)
370 {
371 char buf[100];
372 sprintf(buf, s, t);
373 fatal(buf);
374 }
375 
376 
377 void
378 fatal(char *s)
379 {
380 fflush(stdout);
381 if(s)
382 	fprintf(stderr, "Make: %s.  Stop.\n", s);
383 else
384 	fprintf(stderr, "\nStop.\n");
385 
386 waitstack(0);
387 exit(1);
388 }
389 
390 
391 
392 /* appends to the chain for $? and $^ */
393 chainp
394 appendq(chainp head, char *tail)
395 {
396 chainp p, q;
397 
398 p = ALLOC(chain);
399 p->datap = tail;
400 
401 if(head)
402 	{
403 	for(q = head ; q->nextp ; q = q->nextp)
404 		;
405 	q->nextp = p;
406 	return head;
407 	}
408 else
409 	return p;
410 }
411 
412 
413 
414 
415 
416 /* builds the value for $? and $^ */
417 char *
418 mkqlist(chainp p, char *qbuf)
419 {
420 char *qbufp, *s;
421 
422 if(p == NULL)
423 	return "";
424 
425 qbufp = qbuf;
426 
427 for( ; p ; p = p->nextp)
428 	{
429 	s = p->datap;
430 	if(qbufp+strlen(s) > &qbuf[QBUFMAX-3])
431 		{
432 		fprintf(stderr, "$? list too long\n");
433 		break;
434 		}
435 	while (*s)
436 		*qbufp++ = *s++;
437 	*qbufp++ = ' ';
438 	}
439 *--qbufp = '\0';
440 return qbuf;
441 }
442 
443 wildp
444 iswild(char *name)
445 {
446 char *s;
447 wildp p;
448 
449 for(s=name; *s; ++s)
450 	if(*s == '%')
451 		{
452 		p = ALLOC(wild);
453 		*s = '\0';
454 		p->left = copys(name);
455 		*s = '%';
456 		p->right = copys(s+1);
457 		p->llen = strlen(p->left);
458 		p->rlen = strlen(p->right);
459 		p->totlen = p->llen + p->rlen;
460 		return p;
461 		}
462 return NULL;
463 }
464 
465 
466 char *
467 wildmatch(wildp p, char *name, int len)
468 {
469 char *stem;
470 char *s;
471 char c;
472 
473 if(len < p->totlen ||
474    strncmp(name, p->left, p->llen) ||
475    strncmp(s = name+len-p->rlen, p->right, p->rlen) )
476 	return CHNULL;
477 
478 /*TEMP fprintf(stderr, "wildmatch(%s)=%s%%%s)\n", name,p->left,p->right); */
479 c = *s;
480 *s = '\0';
481 stem = copys(name + p->llen);
482 *s = c;
483 return stem;
484 }
485 
486 
487 
488 /* substitute stem for any % marks */
489 char *
490 wildsub(char *pat, char *stem)
491 {
492 static char temp[100];
493 char *s, *t;
494 
495 s = temp;
496 for(; *pat; ++pat)
497 	if(*pat == '%')
498 		for(t = stem ; *t; )
499 			*s++ = *t++;
500 	else
501 		*s++ = *pat;
502 *s = '\0';
503 return temp;
504 }
505