Replace all RPMERR_* etc uses with corresponding RPMLOG_* levels
[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 "rpmds.h"
10 #include "rpmfi.h"
11 #include "rpmts.h"
12 #include "rpmerr.h"
13
14 #include "debug.h"
15
16 extern int specedit;
17
18 #define SKIPSPACE(s) { while (*(s) && xisspace(*(s))) (s)++; }
19 #define SKIPWHITE(_x)   {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
20 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
21
22 /**
23  * @param p             trigger entry chain
24  * @return              NULL always
25  */
26 static inline
27 struct TriggerFileEntry * freeTriggerFiles(struct TriggerFileEntry * 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 struct Source * freeSources(struct Source * s)
49 {
50     struct Source *r, *t = s;
51
52     while (t != NULL) {
53         r = t;
54         t = t->next;
55         r->fullSource = _free(r->fullSource);
56         r = _free(r);
57     }
58     return NULL;
59 }
60
61 int lookupPackage(rpmSpec spec, const char *name, int flag,Package *pkg)
62 {
63     const char *pname;
64     const char *fullName;
65     Package p;
66     
67     /* "main" package */
68     if (name == NULL) {
69         if (pkg)
70             *pkg = spec->packages;
71         return 0;
72     }
73
74     /* Construct package name */
75   { char *n;
76     if (flag == PART_SUBNAME) {
77         (void) headerNVR(spec->packages->header, &pname, NULL, NULL);
78         fullName = n = alloca(strlen(pname) + 1 + strlen(name) + 1);
79         while (*pname != '\0') *n++ = *pname++;
80         *n++ = '-';
81     } else {
82         fullName = n = alloca(strlen(name)+1);
83     }
84     strcpy(n, name);
85   }
86
87     /* Locate package with fullName */
88     for (p = spec->packages; p != NULL; p = p->next) {
89         (void) headerNVR(p->header, &pname, NULL, NULL);
90         if (pname && (! strcmp(fullName, pname))) {
91             break;
92         }
93     }
94
95     if (pkg)
96         *pkg = p;
97     return ((p == NULL) ? 1 : 0);
98 }
99
100 Package newPackage(rpmSpec spec)
101 {
102     Package p;
103     Package pp;
104
105     p = xcalloc(1, sizeof(*p));
106
107     p->header = headerNew();
108     p->ds = NULL;
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->ds = rpmdsFree(pkg->ds);
160     pkg->fileList = freeStringBuf(pkg->fileList);
161     pkg->fileFile = _free(pkg->fileFile);
162     if (pkg->cpioList) {
163         rpmfi fi = pkg->cpioList;
164         pkg->cpioList = NULL;
165         fi = rpmfiFree(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 struct Source *findSource(rpmSpec spec, int num, int flag)
191 {
192     struct Source *p;
193
194     for (p = spec->sources; p != NULL; p = p->next)
195         if ((num == p->num) && (p->flags & flag)) return p;
196
197     return NULL;
198 }
199
200 int parseNoSource(rpmSpec spec, const char * field, int tag)
201 {
202     const char *f, *fe;
203     const char *name;
204     int num, flag;
205
206     if (tag == RPMTAG_NOSOURCE) {
207         flag = RPMBUILD_ISSOURCE;
208         name = "source";
209     } else {
210         flag = RPMBUILD_ISPATCH;
211         name = "patch";
212     }
213     
214     fe = field;
215     for (f = fe; *f != '\0'; f = fe) {
216         struct Source *p;
217
218         SKIPWHITE(f);
219         if (*f == '\0')
220             break;
221         fe = f;
222         SKIPNONWHITE(fe);
223         if (*fe != '\0') fe++;
224
225         if (parseNum(f, &num)) {
226             rpmlog(RPMLOG_ERR, _("line %d: Bad number: %s\n"),
227                      spec->lineNum, f);
228             return RPMLOG_ERR;
229         }
230
231         if (! (p = findSource(spec, num, flag))) {
232             rpmlog(RPMLOG_ERR, _("line %d: Bad no%s number: %d\n"),
233                      spec->lineNum, name, num);
234             return RPMLOG_ERR;
235         }
236
237         p->flags |= RPMBUILD_ISNO;
238
239     }
240
241     return 0;
242 }
243
244 int addSource(rpmSpec spec, Package pkg, const char *field, int tag)
245 {
246     struct Source *p;
247     int flag = 0;
248     char *name = NULL;
249     char *nump;
250     const char *fieldp = NULL;
251     char buf[BUFSIZ];
252     int num = 0;
253
254     buf[0] = '\0';
255     switch (tag) {
256       case RPMTAG_SOURCE:
257         flag = RPMBUILD_ISSOURCE;
258         name = "source";
259         fieldp = spec->line + 6;
260         break;
261       case RPMTAG_PATCH:
262         flag = RPMBUILD_ISPATCH;
263         name = "patch";
264         fieldp = spec->line + 5;
265         break;
266       case RPMTAG_ICON:
267         flag = RPMBUILD_ISICON;
268         fieldp = NULL;
269         break;
270     }
271
272     /* Get the number */
273     if (tag != RPMTAG_ICON) {
274         /* We already know that a ':' exists, and that there */
275         /* are no spaces before it.                          */
276         /* This also now allows for spaces and tabs between  */
277         /* the number and the ':'                            */
278
279         nump = buf;
280         while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
281             *nump++ = *fieldp++;
282         }
283         *nump = '\0';
284
285         nump = buf;
286         SKIPSPACE(nump);
287         if (nump == NULL || *nump == '\0') {
288             num = 0;
289         } else {
290             if (parseNum(buf, &num)) {
291                 rpmlog(RPMLOG_ERR, _("line %d: Bad %s number: %s\n"),
292                          spec->lineNum, name, spec->line);
293                 return RPMLOG_ERR;
294             }
295         }
296     }
297
298     /* Create the entry and link it in */
299     p = xmalloc(sizeof(*p));
300     p->num = num;
301     p->fullSource = xstrdup(field);
302     p->flags = flag;
303     p->source = strrchr(p->fullSource, '/');
304     if (p->source) {
305         p->source++;
306     } else {
307         p->source = p->fullSource;
308     }
309
310     if (tag != RPMTAG_ICON) {
311         p->next = spec->sources;
312         spec->sources = p;
313     } else {
314         p->next = pkg->icon;
315         pkg->icon = p;
316     }
317
318     spec->numSources++;
319
320     if (tag != RPMTAG_ICON) {
321         const char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
322
323         sprintf(buf, "%s%d",
324                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
325         addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
326         sprintf(buf, "%sURL%d",
327                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
328         addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
329         body = _free(body);
330     }
331     
332     return 0;
333 }
334
335 /**
336  */
337 static inline speclines newSl(void)
338 {
339     speclines sl = NULL;
340     if (specedit) {
341         sl = xmalloc(sizeof(*sl));
342         sl->sl_lines = NULL;
343         sl->sl_nalloc = 0;
344         sl->sl_nlines = 0;
345     }
346     return sl;
347 }
348
349 /**
350  */
351 static inline speclines freeSl(speclines sl)
352 {
353     int i;
354     if (sl == NULL) return NULL;
355     for (i = 0; i < sl->sl_nlines; i++)
356         sl->sl_lines[i] = _free(sl->sl_lines[i]);
357     sl->sl_lines = _free(sl->sl_lines);
358     return _free(sl);
359 }
360
361 /**
362  */
363 static inline spectags newSt(void)
364 {
365     spectags st = NULL;
366     if (specedit) {
367         st = xmalloc(sizeof(*st));
368         st->st_t = NULL;
369         st->st_nalloc = 0;
370         st->st_ntags = 0;
371     }
372     return st;
373 }
374
375 /**
376  */
377 static inline spectags freeSt(spectags st)
378 {
379     int i;
380     if (st == NULL) return NULL;
381     for (i = 0; i < st->st_ntags; i++) {
382         spectag t = st->st_t + i;
383         t->t_lang = _free(t->t_lang);
384         t->t_msgid = _free(t->t_msgid);
385     }
386     st->st_t = _free(st->st_t);
387     return _free(st);
388 }
389
390 rpmSpec newSpec(void)
391 {
392     rpmSpec spec = xcalloc(1, sizeof(*spec));
393     
394     spec->specFile = NULL;
395
396     spec->sl = newSl();
397     spec->st = newSt();
398
399     spec->fileStack = NULL;
400     spec->lbuf[0] = '\0';
401     spec->line = spec->lbuf;
402     spec->nextline = NULL;
403     spec->nextpeekc = '\0';
404     spec->lineNum = 0;
405     spec->readStack = xcalloc(1, sizeof(*spec->readStack));
406     spec->readStack->next = NULL;
407     spec->readStack->reading = 1;
408
409     spec->rootURL = NULL;
410     spec->prep = NULL;
411     spec->build = NULL;
412     spec->install = NULL;
413     spec->check = NULL;
414     spec->clean = NULL;
415
416     spec->sources = NULL;
417     spec->packages = NULL;
418     spec->noSource = 0;
419     spec->numSources = 0;
420
421     spec->sourceRpmName = NULL;
422     spec->sourcePkgId = NULL;
423     spec->sourceHeader = NULL;
424     spec->sourceCpioList = NULL;
425     
426     spec->gotBuildRootURL = 0;
427     spec->buildRootURL = NULL;
428     spec->buildSubdir = NULL;
429
430     spec->passPhrase = NULL;
431     spec->timeCheck = 0;
432     spec->cookie = NULL;
433
434     spec->buildRestrictions = headerNew();
435     spec->BANames = NULL;
436     spec->BACount = 0;
437     spec->recursing = 0;
438     spec->BASpecs = NULL;
439
440     spec->force = 0;
441     spec->anyarch = 0;
442
443     spec->macros = rpmGlobalMacroContext;
444     
445     return spec;
446 }
447
448 rpmSpec freeSpec(rpmSpec spec)
449 {
450     struct ReadLevelEntry *rl;
451
452     if (spec == NULL) return NULL;
453
454     spec->sl = freeSl(spec->sl);
455     spec->st = freeSt(spec->st);
456
457     spec->prep = freeStringBuf(spec->prep);
458     spec->build = freeStringBuf(spec->build);
459     spec->install = freeStringBuf(spec->install);
460     spec->check = freeStringBuf(spec->check);
461     spec->clean = freeStringBuf(spec->clean);
462
463     spec->buildRootURL = _free(spec->buildRootURL);
464     spec->buildSubdir = _free(spec->buildSubdir);
465     spec->rootURL = _free(spec->rootURL);
466     spec->specFile = _free(spec->specFile);
467
468 #ifdef  DEAD
469   { struct OpenFileInfo *ofi;
470     while (spec->fileStack) {
471         ofi = spec->fileStack;
472         spec->fileStack = ofi->next;
473         ofi->next = NULL;
474         ofi->fileName = _free(ofi->fileName);
475         ofi = _free(ofi);
476     }
477   }
478 #else
479     closeSpec(spec);
480 #endif
481
482     while (spec->readStack) {
483         rl = spec->readStack;
484         spec->readStack = rl->next;
485         rl->next = NULL;
486         rl = _free(rl);
487     }
488     
489     spec->sourceRpmName = _free(spec->sourceRpmName);
490     spec->sourcePkgId = _free(spec->sourcePkgId);
491     spec->sourceHeader = headerFree(spec->sourceHeader);
492
493     if (spec->sourceCpioList) {
494         rpmfi fi = spec->sourceCpioList;
495         spec->sourceCpioList = NULL;
496         fi = rpmfiFree(fi);
497     }
498     
499     spec->buildRestrictions = headerFree(spec->buildRestrictions);
500
501     if (!spec->recursing) {
502         if (spec->BASpecs != NULL)
503         while (spec->BACount--) {
504             spec->BASpecs[spec->BACount] =
505                         freeSpec(spec->BASpecs[spec->BACount]);
506         }
507         spec->BASpecs = _free(spec->BASpecs);
508     }
509     spec->BANames = _free(spec->BANames);
510
511     spec->passPhrase = _free(spec->passPhrase);
512     spec->cookie = _free(spec->cookie);
513
514     spec->sources = freeSources(spec->sources);
515     spec->packages = freePackages(spec->packages);
516     
517     spec = _free(spec);
518
519     return spec;
520 }
521
522 struct OpenFileInfo * newOpenFileInfo(void)
523 {
524     struct OpenFileInfo *ofi;
525
526     ofi = xmalloc(sizeof(*ofi));
527     ofi->fd = NULL;
528     ofi->fileName = NULL;
529     ofi->lineNum = 0;
530     ofi->readBuf[0] = '\0';
531     ofi->readPtr = NULL;
532     ofi->next = NULL;
533
534     return ofi;
535 }
536
537 /**
538  * Print copy of spec file, filling in Group/Description/Summary from specspo.
539  * @param spec          spec file control structure
540  */
541 static void
542 printNewSpecfile(rpmSpec spec)
543 {
544     Header h;
545     speclines sl = spec->sl;
546     spectags st = spec->st;
547     const char * msgstr = NULL;
548     int i, j;
549
550     if (sl == NULL || st == NULL)
551         return;
552
553     for (i = 0; i < st->st_ntags; i++) {
554         spectag t = st->st_t + i;
555         const char * tn = rpmTagGetName(t->t_tag);
556         const char * errstr;
557         char fmt[1024];
558
559         fmt[0] = '\0';
560         if (t->t_msgid == NULL)
561             h = spec->packages->header;
562         else {
563             Package pkg;
564             char *fe;
565
566             strcpy(fmt, t->t_msgid);
567             for (fe = fmt; *fe && *fe != '('; fe++)
568                 {} ;
569             if (*fe == '(') *fe = '\0';
570             h = NULL;
571             for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
572                 const char *pkgname;
573                 h = pkg->header;
574                 (void) headerNVR(h, &pkgname, NULL, NULL);
575                 if (!strcmp(pkgname, fmt))
576                     break;
577             }
578             if (pkg == NULL || h == NULL)
579                 h = spec->packages->header;
580         }
581
582         if (h == NULL)
583             continue;
584
585         fmt[0] = '\0';
586         (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tn), "}");
587         msgstr = _free(msgstr);
588
589         /* XXX this should use queryHeader(), but prints out tn as well. */
590         msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
591         if (msgstr == NULL) {
592             rpmlog(RPMLOG_ERR, _("can't query %s: %s\n"), tn, errstr);
593             return;
594         }
595
596         switch(t->t_tag) {
597         case RPMTAG_SUMMARY:
598         case RPMTAG_GROUP:
599             sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
600             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
601                 continue;
602             {   char *buf = xmalloc(strlen(tn) + sizeof(": ") + strlen(msgstr));
603                 (void) stpcpy( stpcpy( stpcpy(buf, tn), ": "), msgstr);
604                 sl->sl_lines[t->t_startx] = buf;
605             }
606             break;
607         case RPMTAG_DESCRIPTION:
608             for (j = 1; j < t->t_nlines; j++) {
609                 if (*sl->sl_lines[t->t_startx + j] == '%')
610                     continue;
611                 sl->sl_lines[t->t_startx + j] =
612                         _free(sl->sl_lines[t->t_startx + j]);
613             }
614             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
615                 sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
616                 continue;
617             }
618             sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
619             if (t->t_nlines > 2)
620                 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
621             break;
622         }
623     }
624     msgstr = _free(msgstr);
625
626     for (i = 0; i < sl->sl_nlines; i++) {
627         const char * s = sl->sl_lines[i];
628         if (s == NULL)
629             continue;
630         printf("%s", s);
631         if (strchr(s, '\n') == NULL && s[strlen(s)-1] != '\n')
632             printf("\n");
633     }
634 }
635
636 int rpmspecQuery(rpmts ts, QVA_t qva, const char * arg)
637 {
638     rpmSpec spec = NULL;
639     Package pkg;
640     char * buildRoot = NULL;
641     int recursing = 0;
642     char * passPhrase = "";
643     char *cookie = NULL;
644     int anyarch = 1;
645     int force = 1;
646     int res = 1;
647     int xx;
648
649     if (qva->qva_showPackage == NULL)
650         goto exit;
651
652     /* FIX: make spec abstract */
653     if (parseSpec(ts, arg, "/", buildRoot, recursing, passPhrase,
654                 cookie, anyarch, force)
655       || (spec = rpmtsSetSpec(ts, NULL)) == NULL)
656     {
657         rpmlog(RPMLOG_ERR,
658                         _("query of specfile %s failed, can't parse\n"), arg);
659         goto exit;
660     }
661
662     res = 0;
663     if (specedit) {
664         printNewSpecfile(spec);
665         goto exit;
666     }
667
668     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next)
669         xx = qva->qva_showPackage(qva, ts, pkg->header);
670
671 exit:
672     spec = freeSpec(spec);
673     return res;
674 }