xref: /plan9-contrib/sys/src/ape/cmd/make/misc.c (revision 401314a3b4602c168a19b28ed47ba5cbefe42fe0)
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 return 0;
194 }
195 
196 /* copy string a into b, substituting for arguments */
197 char *
198 subst(char *a, char *b)
199 {
200 static depth	= 0;
201 char *s;
202 char vname[100];
203 struct varblock *vbp;
204 char closer;
205 
206 if(++depth > 100)
207 	fatal("infinitely recursive macro?");
208 if(a)  while(*a)
209 	{
210 	if(*a!='$' || a[1]=='\0' || *++a=='$')
211 		/* if a non-macro character copy it.  if $$ or $\0, copy $ */
212 		*b++ = *a++;
213 	else	{
214 		s = vname;
215 		if( *a=='(' || *a=='{' )
216 			{
217 			closer = ( *a=='(' ? ')' : '}');
218 			++a;
219 			while(*a == ' ') ++a;
220 			while(*a!=' ' && *a!=closer && *a!='\0') *s++ = *a++;
221 			while(*a!=closer && *a!='\0') ++a;
222 			if(*a == closer) ++a;
223 			}
224 		else	*s++ = *a++;
225 
226 		*s = '\0';
227 		if( (vbp = varptr(vname)) ->varval != 0)
228 			{
229 			b = subst(vbp->varval, b);
230 			vbp->used = YES;
231 			}
232 		}
233 	}
234 
235 *b = '\0';
236 --depth;
237 return b;
238 }
239 
240 void
241 setvar(char *v, char *s, int dyn)
242 {
243 struct varblock *p;
244 
245 p = varptr(v);
246 if( ! p->noreset )
247 	{
248 	p->varval = s;
249 	p->noreset = inarglist;
250 	if(p->used && !dyn)
251 		fprintf(stderr, "Warning: %s changed after being used\n",v);
252 	if(p->export)
253 		{
254 		/* change string pointed to by environment to new v=s */
255 		char *t;
256 		int lenv;
257 		lenv = strlen(v);
258 		*(p->export) = t = (char *) ckalloc(lenv + strlen(s) + 2);
259 		strcpy(t,v);
260 		t[lenv] = '=';
261 		strcpy(t+lenv+1, s);
262 		}
263 	else
264 		p->export = envpp;
265 	}
266 }
267 
268 
269 /* for setting Bradford's *D and *F family of macros whens setting * etc */
270 void
271 set3var(char *macro, char *value)
272 {
273 char *s;
274 char macjunk[8], *lastslash, *dirpart, *filepart;
275 
276 setvar(macro, value, YES);
277 if(value == CHNULL)
278 	dirpart = filepart = CHNULL;
279 else
280 	{
281 	lastslash = CHNULL;
282 	for(s = value; *s; ++s)
283 		if(*s == '/')
284 			lastslash = s;
285 	if(lastslash)
286 		{
287 		dirpart = copys(value);
288 		filepart = dirpart + (lastslash-value);
289 		filepart[-1] = '\0';
290 		}
291 	else
292 		{
293 		dirpart = "";
294 		filepart = value;
295 		}
296 	}
297 setvar(concat(macro, "D", macjunk), dirpart, YES);
298 setvar(concat(macro, "F", macjunk), filepart, YES);
299 }
300 
301 
302 int
303 eqsign(char *a)   /*look for arguments with equal signs but not colons */
304 {
305 char *s, *t;
306 char c;
307 
308 while(*a == ' ') ++a;
309 for(s=a  ;   *s!='\0' && *s!=':'  ; ++s)
310 	if(*s == '=')
311 		{
312 		for(t = a ; *t!='=' && *t!=' ' && *t!='\t' ;  ++t );
313 		c = *t;
314 		*t = '\0';
315 
316 		for(++s; *s==' ' || *s=='\t' ; ++s);
317 		setvar(a, copys(s), NO);
318 		*t = c;
319 		return YES;
320 		}
321 
322 return NO;
323 }
324 
325 struct varblock *
326 varptr(char *v)
327 {
328 struct varblock *vp;
329 
330 /* for compatibility, $(TGS) = $^ */
331 if(equal(v, "TGS") )
332 	v = "^";
333 for(vp = firstvar; vp ; vp = vp->nxtvarblock)
334 	if(equal(v , vp->varname))
335 		return vp;
336 
337 vp = ALLOC(varblock);
338 vp->nxtvarblock = firstvar;
339 firstvar = vp;
340 vp->varname = copys(v);
341 vp->varval = 0;
342 return vp;
343 }
344 
345 int
346 dynmacro(char *line)
347 {
348 char *s;
349 char endc, *endp;
350 if(!isalpha(line[0]))
351 	return NO;
352 for(s=line+1 ; *s && (isalpha(*s) | isdigit(*s)) ; ++s)
353 	;
354 endp = s;
355 while( isspace(*s) )
356 	++s;
357 if(s[0]!=':' || s[1]!='=')
358 	return NO;
359 
360 endc = *endp;
361 *endp = '\0';
362 setvar(line, copys(s+2), YES);
363 *endp = endc;
364 
365 return YES;
366 }
367 
368 
369 void
370 fatal1(char *s, char *t)
371 {
372 char buf[100];
373 sprintf(buf, s, t);
374 fatal(buf);
375 }
376 
377 
378 void
379 fatal(char *s)
380 {
381 fflush(stdout);
382 if(s)
383 	fprintf(stderr, "Make: %s.  Stop.\n", s);
384 else
385 	fprintf(stderr, "\nStop.\n");
386 
387 waitstack(0);
388 exit(1);
389 }
390 
391 
392 
393 /* appends to the chain for $? and $^ */
394 chainp
395 appendq(chainp head, char *tail)
396 {
397 chainp p, q;
398 
399 p = ALLOC(chain);
400 p->datap = tail;
401 
402 if(head)
403 	{
404 	for(q = head ; q->nextp ; q = q->nextp)
405 		;
406 	q->nextp = p;
407 	return head;
408 	}
409 else
410 	return p;
411 }
412 
413 
414 
415 
416 
417 /* builds the value for $? and $^ */
418 char *
419 mkqlist(chainp p, char *qbuf)
420 {
421 char *qbufp, *s;
422 
423 if(p == NULL)
424 	return "";
425 
426 qbufp = qbuf;
427 
428 for( ; p ; p = p->nextp)
429 	{
430 	s = p->datap;
431 	if(qbufp+strlen(s) > &qbuf[QBUFMAX-3])
432 		{
433 		fprintf(stderr, "$? list too long\n");
434 		break;
435 		}
436 	while (*s)
437 		*qbufp++ = *s++;
438 	*qbufp++ = ' ';
439 	}
440 *--qbufp = '\0';
441 return qbuf;
442 }
443 
444 wildp
445 iswild(char *name)
446 {
447 char *s;
448 wildp p;
449 
450 for(s=name; *s; ++s)
451 	if(*s == '%')
452 		{
453 		p = ALLOC(wild);
454 		*s = '\0';
455 		p->left = copys(name);
456 		*s = '%';
457 		p->right = copys(s+1);
458 		p->llen = strlen(p->left);
459 		p->rlen = strlen(p->right);
460 		p->totlen = p->llen + p->rlen;
461 		return p;
462 		}
463 return NULL;
464 }
465 
466 
467 char *
468 wildmatch(wildp p, char *name, int len)
469 {
470 char *stem;
471 char *s;
472 char c;
473 
474 if(len < p->totlen ||
475    strncmp(name, p->left, p->llen) ||
476    strncmp(s = name+len-p->rlen, p->right, p->rlen) )
477 	return CHNULL;
478 
479 /*TEMP fprintf(stderr, "wildmatch(%s)=%s%%%s)\n", name,p->left,p->right); */
480 c = *s;
481 *s = '\0';
482 stem = copys(name + p->llen);
483 *s = c;
484 return stem;
485 }
486 
487 
488 
489 /* substitute stem for any % marks */
490 char *
491 wildsub(char *pat, char *stem)
492 {
493 static char temp[100];
494 char *s, *t;
495 
496 s = temp;
497 for(; *pat; ++pat)
498 	if(*pat == '%')
499 		for(t = stem ; *t; )
500 			*s++ = *t++;
501 	else
502 		*s++ = *pat;
503 *s = '\0';
504 return temp;
505 }
506