- Grand Renaming of rpm data types.
[platform/upstream/rpm.git] / build / spec.c
1 /** \ingroup rpmbuild
2  * \file build/spec.c
3  * Handle spec data structure.
4  */
5
6 #include "system.h"
7
8 #include "buildio.h"
9 #include "rpmfi.h"
10
11 #include "debug.h"
12
13 /*@-redecl@*/
14 extern int specedit;
15 /*@=redecl@*/
16
17 #define SKIPWHITE(_x)   {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
18 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
19
20 /*@access Header @*/    /* compared with NULL */
21 /*@access rpmfi @*/     /* compared with NULL */
22
23 /**
24  * @param p             trigger entry chain
25  * @return              NULL always
26  */
27 static inline
28 /*@null@*/ struct TriggerFileEntry * freeTriggerFiles(/*@only@*/ /*@null@*/ struct TriggerFileEntry * p)
29         /*@modifies p @*/
30 {
31     struct TriggerFileEntry *o, *q = p;
32     
33     while (q != NULL) {
34         o = q;
35         q = q->next;
36         o->fileName = _free(o->fileName);
37         o->script = _free(o->script);
38         o->prog = _free(o->prog);
39         o = _free(o);
40     }
41     return NULL;
42 }
43
44 /**
45  * Destroy source component chain.
46  * @param s             source component chain
47  * @return              NULL always
48  */
49 static inline
50 /*@null@*/ struct Source * freeSources(/*@only@*/ /*@null@*/ struct Source * s)
51         /*@modifies s @*/
52 {
53     struct Source *r, *t = s;
54
55     while (t != NULL) {
56         r = t;
57         t = t->next;
58         r->fullSource = _free(r->fullSource);
59         r = _free(r);
60     }
61     return NULL;
62 }
63
64 int lookupPackage(Spec spec, const char *name, int flag, /*@out@*/Package *pkg)
65 {
66     const char *pname;
67     const char *fullName;
68     Package p;
69     
70     /* "main" package */
71     if (name == NULL) {
72         if (pkg)
73             *pkg = spec->packages;
74         return 0;
75     }
76
77     /* Construct package name */
78   { char *n;
79     if (flag == PART_SUBNAME) {
80         (void) headerNVR(spec->packages->header, &pname, NULL, NULL);
81         fullName = n = alloca(strlen(pname) + 1 + strlen(name) + 1);
82         while (*pname != '\0') *n++ = *pname++;
83         *n++ = '-';
84     } else {
85         fullName = n = alloca(strlen(name)+1);
86     }
87     /*@-mayaliasunique@*/
88     strcpy(n, name);
89     /*@=mayaliasunique@*/
90   }
91
92     /* Locate package with fullName */
93     for (p = spec->packages; p != NULL; p = p->next) {
94         (void) headerNVR(p->header, &pname, NULL, NULL);
95         if (pname && (! strcmp(fullName, pname))) {
96             break;
97         }
98     }
99
100     if (pkg)
101         /*@-dependenttrans@*/ *pkg = p; /*@=dependenttrans@*/
102     return ((p == NULL) ? 1 : 0);
103 }
104
105 Package newPackage(Spec spec)
106 {
107     Package p;
108     Package pp;
109
110     p = xcalloc(1, sizeof(*p));
111
112     p->header = headerNew();
113     p->icon = NULL;
114
115     p->autoProv = 1;
116     p->autoReq = 1;
117     
118 #if 0    
119     p->reqProv = NULL;
120     p->triggers = NULL;
121     p->triggerScripts = NULL;
122 #endif
123
124     p->triggerFiles = NULL;
125     
126     p->fileFile = NULL;
127     p->fileList = NULL;
128
129     p->cpioList = NULL;
130
131     p->preInFile = NULL;
132     p->postInFile = NULL;
133     p->preUnFile = NULL;
134     p->postUnFile = NULL;
135     p->verifyFile = NULL;
136
137     p->specialDoc = NULL;
138
139     if (spec->packages == NULL) {
140         spec->packages = p;
141     } else {
142         /* Always add package to end of list */
143         for (pp = spec->packages; pp->next != NULL; pp = pp->next)
144             {};
145         pp->next = p;
146     }
147     p->next = NULL;
148
149     return p;
150 }
151
152 Package freePackage(Package pkg)
153 {
154     if (pkg == NULL) return NULL;
155     
156     pkg->preInFile = _free(pkg->preInFile);
157     pkg->postInFile = _free(pkg->postInFile);
158     pkg->preUnFile = _free(pkg->preUnFile);
159     pkg->postUnFile = _free(pkg->postUnFile);
160     pkg->verifyFile = _free(pkg->verifyFile);
161
162     pkg->header = headerFree(pkg->header, "pkg->header");
163     pkg->fileList = freeStringBuf(pkg->fileList);
164     pkg->fileFile = _free(pkg->fileFile);
165     if (pkg->cpioList) {
166         rpmfi fi = pkg->cpioList;
167         pkg->cpioList = NULL;
168         fi = rpmfiFree(fi, 1);
169 #ifdef  DYING
170         /*@-refcounttrans@*/ /* FIX: fi needs to be only */
171         fi = _free(fi);
172         /*@=refcounttrans@*/
173 #endif
174     }
175
176     pkg->specialDoc = freeStringBuf(pkg->specialDoc);
177     pkg->icon = freeSources(pkg->icon);
178     pkg->triggerFiles = freeTriggerFiles(pkg->triggerFiles);
179
180     pkg = _free(pkg);
181     return NULL;
182 }
183
184 Package freePackages(Package packages)
185 {
186     Package p;
187
188     while ((p = packages) != NULL) {
189         packages = p->next;
190         p->next = NULL;
191         p = freePackage(p);
192     }
193     return NULL;
194 }
195
196 /**
197  */
198 static inline /*@owned@*/ struct Source *findSource(Spec spec, int num, int flag)
199         /*@*/
200 {
201     struct Source *p;
202
203     for (p = spec->sources; p != NULL; p = p->next)
204         if ((num == p->num) && (p->flags & flag)) return p;
205
206     return NULL;
207 }
208
209 int parseNoSource(Spec spec, const char * field, int tag)
210 {
211     const char *f, *fe;
212     const char *name;
213     int num, flag;
214
215     if (tag == RPMTAG_NOSOURCE) {
216         flag = RPMBUILD_ISSOURCE;
217         name = "source";
218     } else {
219         flag = RPMBUILD_ISPATCH;
220         name = "patch";
221     }
222     
223     fe = field;
224     for (f = fe; *f != '\0'; f = fe) {
225         struct Source *p;
226
227         SKIPWHITE(f);
228         if (*f == '\0')
229             break;
230         fe = f;
231         SKIPNONWHITE(fe);
232         if (*fe != '\0') fe++;
233
234         if (parseNum(f, &num)) {
235             rpmError(RPMERR_BADSPEC, _("line %d: Bad number: %s\n"),
236                      spec->lineNum, f);
237             return RPMERR_BADSPEC;
238         }
239
240         if (! (p = findSource(spec, num, flag))) {
241             rpmError(RPMERR_BADSPEC, _("line %d: Bad no%s number: %d\n"),
242                      spec->lineNum, name, num);
243             return RPMERR_BADSPEC;
244         }
245
246         p->flags |= RPMBUILD_ISNO;
247
248     }
249
250     return 0;
251 }
252
253 int addSource(Spec spec, Package pkg, const char *field, int tag)
254 {
255     struct Source *p;
256     int flag = 0;
257     char *name = NULL;
258     char *nump;
259     const char *fieldp = NULL;
260     char buf[BUFSIZ];
261     int num = 0;
262
263     buf[0] = '\0';
264     /*@-branchstate@*/
265     switch (tag) {
266       case RPMTAG_SOURCE:
267         flag = RPMBUILD_ISSOURCE;
268         name = "source";
269         fieldp = spec->line + 6;
270         break;
271       case RPMTAG_PATCH:
272         flag = RPMBUILD_ISPATCH;
273         name = "patch";
274         fieldp = spec->line + 5;
275         break;
276       case RPMTAG_ICON:
277         flag = RPMBUILD_ISICON;
278         fieldp = NULL;
279         break;
280     }
281     /*@=branchstate@*/
282
283     /* Get the number */
284     if (tag != RPMTAG_ICON) {
285         /* We already know that a ':' exists, and that there */
286         /* are no spaces before it.                          */
287         /* This also now allows for spaces and tabs between  */
288         /* the number and the ':'                            */
289
290         nump = buf;
291         while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
292             *nump++ = *fieldp++;
293         }
294         *nump = '\0';
295
296         nump = buf;
297         SKIPSPACE(nump);
298         if (nump == NULL || *nump == '\0') {
299             num = 0;
300         } else {
301             if (parseNum(buf, &num)) {
302                 rpmError(RPMERR_BADSPEC, _("line %d: Bad %s number: %s\n"),
303                          spec->lineNum, name, spec->line);
304                 return RPMERR_BADSPEC;
305             }
306         }
307     }
308
309     /* Create the entry and link it in */
310     p = xmalloc(sizeof(*p));
311     p->num = num;
312     p->fullSource = xstrdup(field);
313     p->flags = flag;
314     p->source = strrchr(p->fullSource, '/');
315     if (p->source) {
316         p->source++;
317     } else {
318         p->source = p->fullSource;
319     }
320
321     if (tag != RPMTAG_ICON) {
322         p->next = spec->sources;
323         spec->sources = p;
324     } else {
325         p->next = pkg->icon;
326         pkg->icon = p;
327     }
328
329     spec->numSources++;
330
331     if (tag != RPMTAG_ICON) {
332         /*@-nullpass@*/         /* LCL: varargs needs null annotate. */
333         const char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
334         /*@=nullpass@*/
335
336         sprintf(buf, "%s%d",
337                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
338         addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
339         sprintf(buf, "%sURL%d",
340                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
341         addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
342         body = _free(body);
343     }
344     
345     return 0;
346 }
347
348 /**
349  */
350 static inline /*@only@*/ /*@null@*/ speclines newSl(void)
351         /*@*/
352 {
353     speclines sl = NULL;
354     /*@-branchstate@*/
355     if (specedit) {
356         sl = xmalloc(sizeof(*sl));
357         sl->sl_lines = NULL;
358         sl->sl_nalloc = 0;
359         sl->sl_nlines = 0;
360     }
361     /*@=branchstate@*/
362     return sl;
363 }
364
365 /**
366  */
367 static inline /*@null@*/ speclines freeSl(/*@only@*/ /*@null@*/ speclines sl)
368         /*@modifies sl @*/
369 {
370     int i;
371     if (sl == NULL) return NULL;
372     for (i = 0; i < sl->sl_nlines; i++)
373         /*@-unqualifiedtrans@*/
374         sl->sl_lines[i] = _free(sl->sl_lines[i]);
375         /*@=unqualifiedtrans@*/
376     sl->sl_lines = _free(sl->sl_lines);
377     return _free(sl);
378 }
379
380 /**
381  */
382 static inline /*@only@*/ /*@null@*/ spectags newSt(void)
383         /*@*/
384 {
385     spectags st = NULL;
386     /*@-branchstate@*/
387     if (specedit) {
388         st = xmalloc(sizeof(*st));
389         st->st_t = NULL;
390         st->st_nalloc = 0;
391         st->st_ntags = 0;
392     }
393     /*@=branchstate@*/
394     return st;
395 }
396
397 /**
398  */
399 static inline /*@null@*/ spectags freeSt(/*@only@*/ /*@null@*/ spectags st)
400         /*@modifies st @*/
401 {
402     int i;
403     if (st == NULL) return NULL;
404     for (i = 0; i < st->st_ntags; i++) {
405         spectag t = st->st_t + i;
406         t->t_lang = _free(t->t_lang);
407         t->t_msgid = _free(t->t_msgid);
408     }
409     st->st_t = _free(st->st_t);
410     return _free(st);
411 }
412
413 Spec newSpec(void)
414 {
415     Spec spec = xcalloc(1, sizeof(*spec));
416     
417     spec->specFile = NULL;
418     spec->sourceRpmName = NULL;
419
420     spec->sl = newSl();
421     spec->st = newSt();
422
423     spec->fileStack = NULL;
424     spec->lbuf[0] = '\0';
425     spec->line = spec->lbuf;
426     spec->nextline = NULL;
427     spec->nextpeekc = '\0';
428     spec->lineNum = 0;
429     spec->readStack = xcalloc(1, sizeof(*spec->readStack));
430     spec->readStack->next = NULL;
431     spec->readStack->reading = 1;
432
433     spec->rootURL = NULL;
434     spec->prep = NULL;
435     spec->build = NULL;
436     spec->install = NULL;
437     spec->clean = NULL;
438
439     spec->sources = NULL;
440     spec->packages = NULL;
441     spec->noSource = 0;
442     spec->numSources = 0;
443
444     spec->sourceHeader = NULL;
445
446     spec->sourceCpioList = NULL;
447     
448     spec->gotBuildRootURL = 0;
449     spec->buildRootURL = NULL;
450     spec->buildSubdir = NULL;
451
452     spec->passPhrase = NULL;
453     spec->timeCheck = 0;
454     spec->cookie = NULL;
455
456     spec->buildRestrictions = headerNew();
457     spec->BANames = NULL;
458     spec->BACount = 0;
459     spec->recursing = 0;
460     spec->BASpecs = NULL;
461
462     spec->force = 0;
463     spec->anyarch = 0;
464
465 /*@i@*/ spec->macros = rpmGlobalMacroContext;
466     
467     return spec;
468 }
469
470 Spec freeSpec(Spec spec)
471 {
472     struct ReadLevelEntry *rl;
473
474     if (spec == NULL) return NULL;
475
476     spec->sl = freeSl(spec->sl);
477     spec->st = freeSt(spec->st);
478
479     spec->prep = freeStringBuf(spec->prep);
480     spec->build = freeStringBuf(spec->build);
481     spec->install = freeStringBuf(spec->install);
482     spec->clean = freeStringBuf(spec->clean);
483
484     spec->buildRootURL = _free(spec->buildRootURL);
485     spec->buildSubdir = _free(spec->buildSubdir);
486     spec->rootURL = _free(spec->rootURL);
487     spec->specFile = _free(spec->specFile);
488     spec->sourceRpmName = _free(spec->sourceRpmName);
489
490 #ifdef  DEAD
491   { struct OpenFileInfo *ofi;
492     while (spec->fileStack) {
493         ofi = spec->fileStack;
494         spec->fileStack = ofi->next;
495         ofi->next = NULL;
496         ofi->fileName = _free(ofi->fileName);
497         ofi = _free(ofi);
498     }
499   }
500 #else
501     closeSpec(spec);
502 #endif
503
504     while (spec->readStack) {
505         rl = spec->readStack;
506         /*@-dependenttrans@*/
507         spec->readStack = rl->next;
508         /*@=dependenttrans@*/
509         rl->next = NULL;
510         rl = _free(rl);
511     }
512     
513     spec->sourceHeader = headerFree(spec->sourceHeader, "spec->sourceHeader");
514
515     if (spec->sourceCpioList) {
516         rpmfi fi = spec->sourceCpioList;
517         spec->sourceCpioList = NULL;
518         fi = rpmfiFree(fi, 1);
519 #ifdef  DYING
520         /*@-refcounttrans@*/ /* FIX: fi needs to be only */
521         fi = _free(fi);
522         /*@=refcounttrans@*/
523 #endif
524     }
525     
526     spec->buildRestrictions = headerFree(spec->buildRestrictions, "spec->>buildRestrictions");
527
528     if (!spec->recursing) {
529         if (spec->BASpecs != NULL)
530         while (spec->BACount--) {
531             /*@-unqualifiedtrans@*/
532             spec->BASpecs[spec->BACount] =
533                         freeSpec(spec->BASpecs[spec->BACount]);
534             /*@=unqualifiedtrans@*/
535         }
536         /*@-compdef@*/
537         spec->BASpecs = _free(spec->BASpecs);
538         /*@=compdef@*/
539     }
540     spec->BANames = _free(spec->BANames);
541
542     spec->passPhrase = _free(spec->passPhrase);
543     spec->cookie = _free(spec->cookie);
544
545     spec->sources = freeSources(spec->sources);
546     spec->packages = freePackages(spec->packages);
547     
548     spec = _free(spec);
549
550     return spec;
551 }
552
553 /*@only@*/ struct OpenFileInfo * newOpenFileInfo(void)
554 {
555     struct OpenFileInfo *ofi;
556
557     ofi = xmalloc(sizeof(*ofi));
558     ofi->fd = NULL;
559     ofi->fileName = NULL;
560     ofi->lineNum = 0;
561     ofi->readBuf[0] = '\0';
562     ofi->readPtr = NULL;
563     ofi->next = NULL;
564
565     return ofi;
566 }