lib/macro.c: Canonicalize paths in rpmGetPath().
[platform/upstream/rpm.git] / build / spec.c
1 #include "system.h"
2
3 #include "rpmbuild.h"
4 #include "buildio.h"
5
6 extern char *specedit;
7 extern MacroContext globalMacroContext;
8
9 #define SKIPWHITE(_x)   {while(*(_x) && (isspace(*_x) || *(_x) == ',')) (_x)++;}
10 #define SKIPNONWHITE(_x){while(*(_x) &&!(isspace(*_x) || *(_x) == ',')) (_x)++;}
11
12 static inline void freeTriggerFiles(/*@only@*/ struct TriggerFileEntry *p)
13 {
14     struct TriggerFileEntry *o, *q = p;
15     
16     while (q != NULL) {
17         o = q;
18         q = q->next;
19         FREE(o->fileName);
20         FREE(o->script);
21         FREE(o->prog);
22         free(o);
23     }
24 }
25
26 static inline void freeCpioList(/*@only@*/ struct cpioFileMapping *cpioList, int cpioCount)
27 {
28     struct cpioFileMapping *p = cpioList;
29
30     while (cpioCount--) {
31         rpmMessage(RPMMESS_DEBUG, _("archive = %s, fs = %s\n"),
32                    p->archivePath, p->fsPath);
33         FREE(p->archivePath);
34         FREE(p->fsPath);
35         p++;
36     }
37     FREE(cpioList);
38 }
39
40 static inline void freeSources(/*@only@*/ struct Source *s)
41 {
42     struct Source *r, *t = s;
43
44     while (t != NULL) {
45         r = t;
46         t = t->next;
47         FREE(r->fullSource);
48         free(r);
49     }
50 }
51
52 int lookupPackage(Spec spec, const char *name, int flag, /*@out@*/Package *pkg)
53 {
54     const char *pname;
55     const char *fullName;
56     Package p;
57     
58     /* "main" package */
59     if (name == NULL) {
60         if (pkg)
61             *pkg = spec->packages;
62         return 0;
63     }
64
65     /* Construct package name */
66   { char *n;
67     if (flag == PART_SUBNAME) {
68         headerGetEntry(spec->packages->header, RPMTAG_NAME,
69                        NULL, (void **) &pname, NULL);
70         fullName = n = alloca(strlen(pname) + 1 + strlen(name) + 1);
71         while (*pname) *n++ = *pname++;
72         *n++ = '-';
73     } else {
74         fullName = n = alloca(strlen(name)+1);
75     }
76     strcpy(n, name);
77   }
78
79     /* Locate package with fullName */
80     for (p = spec->packages; p != NULL; p = p->next) {
81         headerGetEntry(p->header, RPMTAG_NAME, NULL, (void **) &pname, NULL);
82         if (pname && (! strcmp(fullName, pname))) {
83             break;
84         }
85     }
86
87     if (pkg)
88         *pkg = p;
89     return ((p == NULL) ? 1 : 0);
90 }
91
92 Package newPackage(Spec spec)
93 {
94     Package p;
95     Package pp;
96
97     p = xmalloc(sizeof(*p));
98
99     p->header = headerNew();
100     p->icon = NULL;
101
102     p->autoProv = 1;
103     p->autoReq = 1;
104     
105 #if 0    
106     p->reqProv = NULL;
107     p->triggers = NULL;
108     p->triggerScripts = NULL;
109 #endif
110
111     p->triggerFiles = NULL;
112     
113     p->fileFile = NULL;
114     p->fileList = NULL;
115
116     p->cpioList = NULL;
117     p->cpioCount = 0;
118
119     p->preInFile = NULL;
120     p->postInFile = NULL;
121     p->preUnFile = NULL;
122     p->postUnFile = NULL;
123     p->verifyFile = NULL;
124
125     p->specialDoc = NULL;
126
127     if (spec->packages == NULL) {
128         spec->packages = p;
129     } else {
130         /* Always add package to end of list */
131         for (pp = spec->packages; pp->next != NULL; pp = pp->next)
132             ;
133         pp->next = p;
134     }
135     p->next = NULL;
136
137     return p;
138 }
139
140 void freePackage(/*@only@*/ Package p)
141 {
142     if (p == NULL)
143         return;
144     
145     FREE(p->preInFile);
146     FREE(p->postInFile);
147     FREE(p->preUnFile);
148     FREE(p->postUnFile);
149     FREE(p->verifyFile);
150
151     headerFree(p->header);
152     freeStringBuf(p->fileList);
153     FREE(p->fileFile);
154     freeCpioList(p->cpioList, p->cpioCount);
155
156     freeStringBuf(p->specialDoc);
157
158     freeSources(p->icon);
159
160     freeTriggerFiles(p->triggerFiles);
161
162     free(p);
163 }
164
165 void freePackages(Spec spec)
166 {
167     Package p;
168
169     while (spec->packages) {
170         p = spec->packages;
171         spec->packages = spec->packages->next;
172         p->next = NULL;
173         freePackage(p);
174     }
175 }
176
177 static inline /*@owned@*/ struct Source *findSource(Spec spec, int num, int flag)
178 {
179     struct Source *p;
180
181     for (p = spec->sources; p != NULL; p = p->next) {
182         if ((num == p->num) && (p->flags & flag)) {
183             return p;
184         }
185     }
186
187     return NULL;
188 }
189
190 #ifdef  UNUSED
191 static char *getSourceAux(Spec spec, int num, int flag, int full)
192 {
193     struct Source *p = spec->sources;
194
195     p = findSource(spec, num, flag);
196
197     return (p) ? (full ? p->fullSource : p->source) : NULL;
198 }
199
200 static char *getSource(Spec spec, int num, int flag)
201 {
202     return getSourceAux(spec, num, flag, 0);
203 }
204
205 static char *getFullSource(Spec spec, int num, int flag)
206 {
207     return getSourceAux(spec, num, flag, 1);
208 }
209 #endif  /* UNUSED */
210
211 int parseNoSource(Spec spec, const char *field, int tag)
212 {
213     const char *f, *fe;
214     const char *name;
215     int num, flag;
216
217     if (tag == RPMTAG_NOSOURCE) {
218         flag = RPMBUILD_ISSOURCE;
219         name = "source";
220     } else {
221         flag = RPMBUILD_ISPATCH;
222         name = "patch";
223     }
224     
225     fe = field;
226     for (f = fe; *f; f = fe) {
227         struct Source *p;
228
229         SKIPWHITE(f);
230         if (*f == '\0')
231             break;
232         fe = f;
233         SKIPNONWHITE(fe);
234         if (*fe) fe++;
235
236         if (parseNum(f, &num)) {
237             rpmError(RPMERR_BADSPEC, _("line %d: Bad number: %s"),
238                      spec->lineNum, f);
239             return RPMERR_BADSPEC;
240         }
241
242         if (! (p = findSource(spec, num, flag))) {
243             rpmError(RPMERR_BADSPEC, _("line %d: Bad no%s number: %d"),
244                      spec->lineNum, name, num);
245             return RPMERR_BADSPEC;
246         }
247
248         p->flags |= RPMBUILD_ISNO;
249
250     }
251
252     return 0;
253 }
254
255 int addSource(Spec spec, Package pkg, const char *field, int tag)
256 {
257     struct Source *p;
258     int flag = 0;
259     char *name = NULL;
260     char *nump;
261     const char *fieldp = NULL;
262     char buf[BUFSIZ];
263     int num = 0;
264
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
282     /* Get the number */
283     if (tag != RPMTAG_ICON) {
284         /* We already know that a ':' exists, and that there */
285         /* are no spaces before it.                          */
286         /* This also now allows for spaces and tabs between  */
287         /* the number and the ':'                            */
288
289         nump = buf;
290         while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
291             *nump++ = *fieldp++;
292         }
293         *nump = '\0';
294
295         nump = buf;
296         SKIPSPACE(nump);
297         if (! *nump) {
298             num = 0;
299         } else {
300             if (parseNum(buf, &num)) {
301                 rpmError(RPMERR_BADSPEC, _("line %d: Bad %s number: %s\n"),
302                          spec->lineNum, name, spec->line);
303                 return RPMERR_BADSPEC;
304             }
305         }
306     }
307
308     /* Create the entry and link it in */
309     p = xmalloc(sizeof(struct Source));
310     p->num = num;
311     p->fullSource = xstrdup(field);
312     p->source = strrchr(p->fullSource, '/');
313     p->flags = flag;
314     if (p->source) {
315         p->source++;
316     } else {
317         p->source = p->fullSource;
318     }
319
320     if (tag != RPMTAG_ICON) {
321         p->next = spec->sources;
322         spec->sources = p;
323     } else {
324         p->next = pkg->icon;
325         pkg->icon = p;
326     }
327
328     spec->numSources++;
329
330     if (tag != RPMTAG_ICON) {
331         const char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
332
333         sprintf(buf, "%s%d",
334                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
335         addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
336         sprintf(buf, "%sURL%d",
337                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
338         addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
339         xfree(body);
340     }
341     
342     return 0;
343 }
344
345 static inline struct speclines * newSl(void)
346 {
347     struct speclines *sl;
348     if (specedit == NULL)
349         return NULL;
350     sl = xmalloc(sizeof(struct speclines));
351     sl->sl_lines = NULL;
352     sl->sl_nalloc = 0;
353     sl->sl_nlines = 0;
354     return sl;
355 }
356
357 static inline void freeSl(/*@only@*/struct speclines *sl)
358 {
359     int i;
360     if (sl == NULL)
361         return;
362     for (i = 0; i < sl->sl_nlines; i++)
363         FREE(sl->sl_lines[i]);
364     FREE(sl->sl_lines);
365     free(sl);
366 }
367
368 static inline struct spectags * newSt(void)
369 {
370     struct spectags *st;
371     if (specedit == NULL)
372         return NULL;
373     st = xmalloc(sizeof(struct spectags));
374     st->st_t = NULL;
375     st->st_nalloc = 0;
376     st->st_ntags = 0;
377     return st;
378 }
379
380 static inline void freeSt(/*@only@*/struct spectags *st)
381 {
382     int i;
383     if (st == NULL)
384         return;
385     for (i = 0; i < st->st_ntags; i++) {
386         struct spectag *t = st->st_t + i;
387         FREE(t->t_lang);
388         FREE(t->t_msgid);
389     }
390     FREE(st->st_t);
391     free(st);
392 }
393
394 Spec newSpec(void)
395 {
396     Spec spec;
397
398     spec = (Spec)xmalloc(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 = xmalloc(sizeof(struct ReadLevelEntry));
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->sourceCpioCount = 0;
430     spec->sourceCpioList = NULL;
431     
432     spec->gotBuildRootURL = 0;
433     spec->buildRootURL = NULL;
434     spec->buildSubdir = NULL;
435
436     spec->passPhrase = NULL;
437     spec->timeCheck = 0;
438     spec->cookie = NULL;
439
440     spec->buildRestrictions = headerNew();
441     spec->buildArchitectures = NULL;
442     spec->buildArchitectureCount = 0;
443     spec->inBuildArchitectures = 0;
444     spec->buildArchitectureSpecs = NULL;
445
446     spec->force = 0;
447     spec->anyarch = 0;
448
449     spec->macros = &globalMacroContext;
450     
451     return spec;
452 }
453
454 void freeSpec(/*@only@*/ Spec spec)
455 {
456     struct OpenFileInfo *ofi;
457     struct ReadLevelEntry *rl;
458
459     freeSl(spec->sl);   spec->sl = NULL;
460     freeSt(spec->st);   spec->st = NULL;
461
462     freeStringBuf(spec->prep);  spec->prep = NULL;
463     freeStringBuf(spec->build); spec->build = NULL;
464     freeStringBuf(spec->install); spec->install = NULL;
465     freeStringBuf(spec->clean); spec->clean = NULL;
466
467     FREE(spec->buildRootURL);
468     FREE(spec->buildSubdir);
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 }