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