doxygen annotations for build/*.
[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 extern int specedit;
13 extern MacroContext rpmGlobalMacroContext;
14
15 #define SKIPWHITE(_x)   {while(*(_x) && (isspace(*_x) || *(_x) == ',')) (_x)++;}
16 #define SKIPNONWHITE(_x){while(*(_x) &&!(isspace(*_x) || *(_x) == ',')) (_x)++;}
17
18 /**
19  */
20 static inline void freeTriggerFiles(/*@only@*/ struct TriggerFileEntry *p)
21 {
22     struct TriggerFileEntry *o, *q = p;
23     
24     while (q != NULL) {
25         o = q;
26         q = q->next;
27         FREE(o->fileName);
28         FREE(o->script);
29         FREE(o->prog);
30         free(o);
31     }
32 }
33
34 /**
35  */
36 static inline void freeCpioList(/*@only@*/ struct cpioFileMapping *cpioList, int cpioCount)
37 {
38     struct cpioFileMapping *p = cpioList;
39
40     while (cpioCount--) {
41         rpmMessage(RPMMESS_DEBUG, _("archive = %s, fs = %s\n"),
42                    p->archivePath, p->fsPath);
43         FREE(p->archivePath);
44         FREE(p->fsPath);
45         p++;
46     }
47     FREE(cpioList);
48 }
49
50 /**
51  */
52 static inline void freeSources(/*@only@*/ struct Source *s)
53 {
54     struct Source *r, *t = s;
55
56     while (t != NULL) {
57         r = t;
58         t = t->next;
59         FREE(r->fullSource);
60         free(r);
61     }
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         headerNVR(spec->packages->header, &pname, NULL, NULL);
81         fullName = n = alloca(strlen(pname) + 1 + strlen(name) + 1);
82         while (*pname) *n++ = *pname++;
83         *n++ = '-';
84     } else {
85         fullName = n = alloca(strlen(name)+1);
86     }
87     strcpy(n, name);
88   }
89
90     /* Locate package with fullName */
91     for (p = spec->packages; p != NULL; p = p->next) {
92         headerNVR(p->header, &pname, NULL, NULL);
93         if (pname && (! strcmp(fullName, pname))) {
94             break;
95         }
96     }
97
98     if (pkg)
99         *pkg = p;
100     return ((p == NULL) ? 1 : 0);
101 }
102
103 Package newPackage(Spec spec)
104 {
105     Package p;
106     Package pp;
107
108     p = xmalloc(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     p->cpioCount = 0;
129
130     p->preInFile = NULL;
131     p->postInFile = NULL;
132     p->preUnFile = NULL;
133     p->postUnFile = NULL;
134     p->verifyFile = NULL;
135
136     p->specialDoc = NULL;
137
138     if (spec->packages == NULL) {
139         spec->packages = p;
140     } else {
141         /* Always add package to end of list */
142         for (pp = spec->packages; pp->next != NULL; pp = pp->next)
143             ;
144         pp->next = p;
145     }
146     p->next = NULL;
147
148     return p;
149 }
150
151 void freePackage(/*@only@*/ Package p)
152 {
153     if (p == NULL)
154         return;
155     
156     FREE(p->preInFile);
157     FREE(p->postInFile);
158     FREE(p->preUnFile);
159     FREE(p->postUnFile);
160     FREE(p->verifyFile);
161
162     headerFree(p->header);
163     freeStringBuf(p->fileList);
164     FREE(p->fileFile);
165     freeCpioList(p->cpioList, p->cpioCount);
166
167     freeStringBuf(p->specialDoc);
168
169     freeSources(p->icon);
170
171     freeTriggerFiles(p->triggerFiles);
172
173     free(p);
174 }
175
176 void freePackages(Spec spec)
177 {
178     Package p;
179
180     while ((p = spec->packages) != NULL) {
181         spec->packages = p->next;
182         p->next = NULL;
183         freePackage(p);
184     }
185 }
186
187 /**
188  */
189 static inline /*@owned@*/ struct Source *findSource(Spec spec, int num, int flag)
190 {
191     struct Source *p;
192
193     for (p = spec->sources; p != NULL; p = p->next) {
194         if ((num == p->num) && (p->flags & flag)) {
195             return p;
196         }
197     }
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; 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) fe++;
226
227         if (parseNum(f, &num)) {
228             rpmError(RPMERR_BADSPEC, _("line %d: Bad number: %s"),
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"),
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     switch (tag) {
257       case RPMTAG_SOURCE:
258         flag = RPMBUILD_ISSOURCE;
259         name = "source";
260         fieldp = spec->line + 6;
261         break;
262       case RPMTAG_PATCH:
263         flag = RPMBUILD_ISPATCH;
264         name = "patch";
265         fieldp = spec->line + 5;
266         break;
267       case RPMTAG_ICON:
268         flag = RPMBUILD_ISICON;
269         fieldp = NULL;
270         break;
271     }
272
273     /* Get the number */
274     if (tag != RPMTAG_ICON) {
275         /* We already know that a ':' exists, and that there */
276         /* are no spaces before it.                          */
277         /* This also now allows for spaces and tabs between  */
278         /* the number and the ':'                            */
279
280         nump = buf;
281         while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
282             *nump++ = *fieldp++;
283         }
284         *nump = '\0';
285
286         nump = buf;
287         SKIPSPACE(nump);
288         if (! *nump) {
289             num = 0;
290         } else {
291             if (parseNum(buf, &num)) {
292                 rpmError(RPMERR_BADSPEC, _("line %d: Bad %s number: %s\n"),
293                          spec->lineNum, name, spec->line);
294                 return RPMERR_BADSPEC;
295             }
296         }
297     }
298
299     /* Create the entry and link it in */
300     p = xmalloc(sizeof(struct Source));
301     p->num = num;
302     p->fullSource = xstrdup(field);
303     p->source = strrchr(p->fullSource, '/');
304     p->flags = flag;
305     if (p->source) {
306         p->source++;
307     } else {
308         p->source = p->fullSource;
309     }
310
311     if (tag != RPMTAG_ICON) {
312         p->next = spec->sources;
313         spec->sources = p;
314     } else {
315         p->next = pkg->icon;
316         pkg->icon = p;
317     }
318
319     spec->numSources++;
320
321     if (tag != RPMTAG_ICON) {
322         const char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
323
324         sprintf(buf, "%s%d",
325                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
326         addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
327         sprintf(buf, "%sURL%d",
328                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
329         addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
330         free((void *)body);
331     }
332     
333     return 0;
334 }
335
336 /**
337  */
338 static inline struct speclines * newSl(void)
339 {
340     struct speclines *sl = NULL;
341     if (specedit) {
342         sl = xmalloc(sizeof(struct speclines));
343         sl->sl_lines = NULL;
344         sl->sl_nalloc = 0;
345         sl->sl_nlines = 0;
346     }
347     return sl;
348 }
349
350 /**
351  */
352 static inline void freeSl(/*@only@*/struct speclines *sl)
353 {
354     int i;
355     if (sl == NULL)
356         return;
357     for (i = 0; i < sl->sl_nlines; i++)
358         FREE(sl->sl_lines[i]);
359     FREE(sl->sl_lines);
360     free(sl);
361 }
362
363 /**
364  */
365 static inline struct spectags * newSt(void)
366 {
367     struct spectags *st = NULL;
368     if (specedit) {
369         st = xmalloc(sizeof(struct spectags));
370         st->st_t = NULL;
371         st->st_nalloc = 0;
372         st->st_ntags = 0;
373     }
374     return st;
375 }
376
377 /**
378  */
379 static inline void freeSt(/*@only@*/struct spectags *st)
380 {
381     int i;
382     if (st == NULL)
383         return;
384     for (i = 0; i < st->st_ntags; i++) {
385         struct spectag *t = st->st_t + i;
386         FREE(t->t_lang);
387         FREE(t->t_msgid);
388     }
389     FREE(st->st_t);
390     free(st);
391 }
392
393 Spec newSpec(void)
394 {
395     Spec spec;
396
397     spec = (Spec)xmalloc(sizeof *spec);
398     
399     spec->specFile = NULL;
400     spec->sourceRpmName = NULL;
401
402     spec->sl = newSl();
403     spec->st = newSt();
404
405     spec->fileStack = NULL;
406     spec->lbuf[0] = '\0';
407     spec->line = spec->lbuf;
408     spec->nextline = NULL;
409     spec->nextpeekc = '\0';
410     spec->lineNum = 0;
411     spec->readStack = xmalloc(sizeof(struct ReadLevelEntry));
412     spec->readStack->next = NULL;
413     spec->readStack->reading = 1;
414
415     spec->rootURL = NULL;
416     spec->prep = NULL;
417     spec->build = NULL;
418     spec->install = NULL;
419     spec->clean = NULL;
420
421     spec->sources = NULL;
422     spec->packages = NULL;
423     spec->noSource = 0;
424     spec->numSources = 0;
425
426     spec->sourceHeader = NULL;
427
428     spec->sourceCpioCount = 0;
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->buildArchitectures = NULL;
441     spec->buildArchitectureCount = 0;
442     spec->inBuildArchitectures = 0;
443     spec->buildArchitectureSpecs = NULL;
444
445     spec->force = 0;
446     spec->anyarch = 0;
447
448     spec->macros = &rpmGlobalMacroContext;
449     
450     return spec;
451 }
452
453 void freeSpec(/*@only@*/ Spec spec)
454 {
455     struct OpenFileInfo *ofi;
456     struct ReadLevelEntry *rl;
457
458     freeSl(spec->sl);   spec->sl = NULL;
459     freeSt(spec->st);   spec->st = NULL;
460
461     freeStringBuf(spec->prep);  spec->prep = NULL;
462     freeStringBuf(spec->build); spec->build = NULL;
463     freeStringBuf(spec->install); spec->install = NULL;
464     freeStringBuf(spec->clean); spec->clean = NULL;
465
466     FREE(spec->buildRootURL);
467     FREE(spec->buildSubdir);
468     FREE(spec->rootURL);
469     FREE(spec->specFile);
470     FREE(spec->sourceRpmName);
471
472     while (spec->fileStack) {
473         ofi = spec->fileStack;
474         spec->fileStack = spec->fileStack->next;
475         ofi->next = NULL;
476         FREE(ofi->fileName);
477         free(ofi);
478     }
479
480     while (spec->readStack) {
481         rl = spec->readStack;
482         spec->readStack = spec->readStack->next;
483         rl->next = NULL;
484         free(rl);
485     }
486     
487     if (spec->sourceHeader != NULL) {
488         headerFree(spec->sourceHeader);
489         spec->sourceHeader = NULL;
490     }
491
492     freeCpioList(spec->sourceCpioList, spec->sourceCpioCount);
493     spec->sourceCpioList = NULL;
494     
495     headerFree(spec->buildRestrictions);
496     spec->buildRestrictions = NULL;
497
498     if (!spec->inBuildArchitectures) {
499         while (spec->buildArchitectureCount--) {
500             freeSpec(
501                 spec->buildArchitectureSpecs[spec->buildArchitectureCount]);
502         }
503         FREE(spec->buildArchitectureSpecs);
504     }
505     FREE(spec->buildArchitectures);
506
507     FREE(spec->passPhrase);
508     FREE(spec->cookie);
509
510     freeSources(spec->sources); spec->sources = NULL;
511     freePackages(spec);
512     closeSpec(spec);
513     
514     free(spec);
515 }
516
517 /*@only@*/ struct OpenFileInfo * newOpenFileInfo(void)
518 {
519     struct OpenFileInfo *ofi;
520
521     ofi = xmalloc(sizeof(struct OpenFileInfo));
522     ofi->fd = NULL;
523     ofi->fileName = NULL;
524     ofi->lineNum = 0;
525     ofi->readBuf[0] = '\0';
526     ofi->readPtr = NULL;
527     ofi->next = NULL;
528
529     return ofi;
530 }