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