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