Eliminate bogus const's from spec structure
[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 <rpm/header.h>
9 #include <rpm/rpmds.h>
10 #include <rpm/rpmfi.h>
11 #include <rpm/rpmts.h>
12 #include <rpm/rpmlog.h>
13 #include <rpm/rpmfileutil.h>
14
15 #include "build/buildio.h"
16 #include "rpmio/rpmlua.h"
17
18 #include "debug.h"
19
20 extern int specedit;
21
22 #define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
23 #define SKIPWHITE(_x)   {while(*(_x) && (risspace(*_x) || *(_x) == ',')) (_x)++;}
24 #define SKIPNONWHITE(_x){while(*(_x) &&!(risspace(*_x) || *(_x) == ',')) (_x)++;}
25
26 /**
27  * @param p             trigger entry chain
28  * @return              NULL always
29  */
30 static inline
31 struct TriggerFileEntry * freeTriggerFiles(struct TriggerFileEntry * p)
32 {
33     struct TriggerFileEntry *o, *q = p;
34     
35     while (q != NULL) {
36         o = q;
37         q = q->next;
38         o->fileName = _free(o->fileName);
39         o->script = _free(o->script);
40         o->prog = _free(o->prog);
41         o = _free(o);
42     }
43     return NULL;
44 }
45
46 /**
47  * Destroy source component chain.
48  * @param s             source component chain
49  * @return              NULL always
50  */
51 static inline
52 struct Source * freeSources(struct Source * s)
53 {
54     struct Source *r, *t = s;
55
56     while (t != NULL) {
57         r = t;
58         t = t->next;
59         r->fullSource = _free(r->fullSource);
60         r = _free(r);
61     }
62     return NULL;
63 }
64
65 rpmRC lookupPackage(rpmSpec spec, const char *name, int flag,Package *pkg)
66 {
67     const char *pname;
68     const char *fullName;
69     Package p;
70     
71     /* "main" package */
72     if (name == NULL) {
73         if (pkg)
74             *pkg = spec->packages;
75         return RPMRC_OK;
76     }
77
78     /* Construct package name */
79   { char *n;
80     if (flag == PART_SUBNAME) {
81         (void) headerNVR(spec->packages->header, &pname, NULL, NULL);
82         fullName = n = alloca(strlen(pname) + 1 + strlen(name) + 1);
83         while (*pname != '\0') *n++ = *pname++;
84         *n++ = '-';
85     } else {
86         fullName = n = alloca(strlen(name)+1);
87     }
88     strcpy(n, name);
89   }
90
91     /* Locate package with fullName */
92     for (p = spec->packages; p != NULL; p = p->next) {
93         (void) headerNVR(p->header, &pname, NULL, NULL);
94         if (pname && (! strcmp(fullName, pname))) {
95             break;
96         }
97     }
98
99     if (pkg)
100         *pkg = p;
101     return ((p == NULL) ? RPMRC_FAIL : RPMRC_OK);
102 }
103
104 Package newPackage(rpmSpec spec)
105 {
106     Package p;
107     Package pp;
108
109     p = xcalloc(1, sizeof(*p));
110
111     p->header = headerNew();
112     p->ds = NULL;
113     p->icon = NULL;
114
115     p->autoProv = 1;
116     p->autoReq = 1;
117     
118 #if 0    
119     p->reqProv = NULL;
120     p->triggers = NULL;
121     p->triggerScripts = NULL;
122 #endif
123
124     p->triggerFiles = NULL;
125     
126     p->fileFile = NULL;
127     p->fileList = NULL;
128
129     p->cpioList = NULL;
130
131     p->preInFile = NULL;
132     p->postInFile = NULL;
133     p->preUnFile = NULL;
134     p->postUnFile = NULL;
135     p->verifyFile = NULL;
136
137     p->specialDoc = NULL;
138
139     if (spec->packages == NULL) {
140         spec->packages = p;
141     } else {
142         /* Always add package to end of list */
143         for (pp = spec->packages; pp->next != NULL; pp = pp->next)
144             {};
145         pp->next = p;
146     }
147     p->next = NULL;
148
149     return p;
150 }
151
152 Package freePackage(Package pkg)
153 {
154     if (pkg == NULL) return NULL;
155     
156     pkg->preInFile = _free(pkg->preInFile);
157     pkg->postInFile = _free(pkg->postInFile);
158     pkg->preUnFile = _free(pkg->preUnFile);
159     pkg->postUnFile = _free(pkg->postUnFile);
160     pkg->verifyFile = _free(pkg->verifyFile);
161
162     pkg->header = headerFree(pkg->header);
163     pkg->ds = rpmdsFree(pkg->ds);
164     pkg->fileList = freeStringBuf(pkg->fileList);
165     pkg->fileFile = _free(pkg->fileFile);
166     if (pkg->cpioList) {
167         rpmfi fi = pkg->cpioList;
168         pkg->cpioList = NULL;
169         fi = rpmfiFree(fi);
170     }
171
172     pkg->specialDoc = freeStringBuf(pkg->specialDoc);
173     pkg->icon = freeSources(pkg->icon);
174     pkg->triggerFiles = freeTriggerFiles(pkg->triggerFiles);
175
176     pkg = _free(pkg);
177     return NULL;
178 }
179
180 Package freePackages(Package packages)
181 {
182     Package p;
183
184     while ((p = packages) != NULL) {
185         packages = p->next;
186         p->next = NULL;
187         p = freePackage(p);
188     }
189     return NULL;
190 }
191
192 /**
193  */
194 static inline struct Source *findSource(rpmSpec spec, int num, int flag)
195 {
196     struct Source *p;
197
198     for (p = spec->sources; p != NULL; p = p->next)
199         if ((num == p->num) && (p->flags & flag)) return p;
200
201     return NULL;
202 }
203
204 int parseNoSource(rpmSpec spec, const char * field, rpmTag tag)
205 {
206     const char *f, *fe;
207     const char *name;
208     int num, flag;
209
210     if (tag == RPMTAG_NOSOURCE) {
211         flag = RPMBUILD_ISSOURCE;
212         name = "source";
213     } else {
214         flag = RPMBUILD_ISPATCH;
215         name = "patch";
216     }
217     
218     fe = field;
219     for (f = fe; *f != '\0'; f = fe) {
220         struct Source *p;
221
222         SKIPWHITE(f);
223         if (*f == '\0')
224             break;
225         fe = f;
226         SKIPNONWHITE(fe);
227         if (*fe != '\0') fe++;
228
229         if (parseNum(f, &num)) {
230             rpmlog(RPMLOG_ERR, _("line %d: Bad number: %s\n"),
231                      spec->lineNum, f);
232             return RPMRC_FAIL;
233         }
234
235         if (! (p = findSource(spec, num, flag))) {
236             rpmlog(RPMLOG_ERR, _("line %d: Bad no%s number: %d\n"),
237                      spec->lineNum, name, num);
238             return RPMRC_FAIL;
239         }
240
241         p->flags |= RPMBUILD_ISNO;
242
243     }
244
245     return 0;
246 }
247
248 int addSource(rpmSpec spec, Package pkg, const char *field, rpmTag tag)
249 {
250     struct Source *p;
251     int flag = 0;
252     const char *name = NULL;
253     char *nump;
254     char *fieldp = NULL;
255     char *buf = NULL;
256     int num = 0;
257
258     switch ((rpm_tag_t) tag) {
259       case RPMTAG_SOURCE:
260         flag = RPMBUILD_ISSOURCE;
261         name = "source";
262         fieldp = spec->line + 6;
263         break;
264       case RPMTAG_PATCH:
265         flag = RPMBUILD_ISPATCH;
266         name = "patch";
267         fieldp = spec->line + 5;
268         break;
269       case RPMTAG_ICON:
270         flag = RPMBUILD_ISICON;
271         fieldp = NULL;
272         break;
273     }
274
275     /* Get the number */
276     if (tag != RPMTAG_ICON) {
277         /* We already know that a ':' exists, and that there */
278         /* are no spaces before it.                          */
279         /* This also now allows for spaces and tabs between  */
280         /* the number and the ':'                            */
281         char ch;
282         char *fieldp_backup = fieldp;
283
284         while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
285             fieldp++;
286         }
287         ch = *fieldp;
288         *fieldp = '\0';
289
290         nump = fieldp_backup;
291         SKIPSPACE(nump);
292         if (nump == NULL || *nump == '\0') {
293             num = 0;
294         } else {
295             if (parseNum(fieldp_backup, &num)) {
296                 rpmlog(RPMLOG_ERR, _("line %d: Bad %s number: %s\n"),
297                          spec->lineNum, name, spec->line);
298                 *fieldp = ch;
299                 return RPMRC_FAIL;
300             }
301         }
302         *fieldp = ch;
303     }
304
305     /* Create the entry and link it in */
306     p = xmalloc(sizeof(*p));
307     p->num = num;
308     p->fullSource = xstrdup(field);
309     p->flags = flag;
310     p->source = strrchr(p->fullSource, '/');
311     if (p->source) {
312         p->source++;
313     } else {
314         p->source = p->fullSource;
315     }
316
317     if (tag != RPMTAG_ICON) {
318         p->next = spec->sources;
319         spec->sources = p;
320     } else {
321         p->next = pkg->icon;
322         pkg->icon = p;
323     }
324
325     spec->numSources++;
326
327     if (tag != RPMTAG_ICON) {
328         char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
329
330         rasprintf(&buf, "%s%d",
331                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
332         addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
333         free(buf);
334         rasprintf(&buf, "%sURL%d",
335                 (flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
336         addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
337         free(buf);
338 #ifdef WITH_LUA
339         {
340         rpmlua lua = NULL; /* global state */
341         const char * what = (flag & RPMBUILD_ISPATCH) ? "patches" : "sources";
342         rpmluaPushTable(lua, what);
343         rpmluav var = rpmluavNew();
344         rpmluavSetListMode(var, 1);
345         rpmluavSetValue(var, RPMLUAV_STRING, body);
346         rpmluaSetVar(lua, var);
347         var = rpmluavFree(var);
348         rpmluaPop(lua);
349         }
350 #endif
351         body = _free(body);
352     }
353     
354     return 0;
355 }
356
357 /**
358  */
359 static inline speclines newSl(void)
360 {
361     speclines sl = NULL;
362     if (specedit) {
363         sl = xmalloc(sizeof(*sl));
364         sl->sl_lines = NULL;
365         sl->sl_nalloc = 0;
366         sl->sl_nlines = 0;
367     }
368     return sl;
369 }
370
371 /**
372  */
373 static inline speclines freeSl(speclines sl)
374 {
375     int i;
376     if (sl == NULL) return NULL;
377     for (i = 0; i < sl->sl_nlines; i++)
378         sl->sl_lines[i] = _free(sl->sl_lines[i]);
379     sl->sl_lines = _free(sl->sl_lines);
380     return _free(sl);
381 }
382
383 /**
384  */
385 static inline spectags newSt(void)
386 {
387     spectags st = NULL;
388     if (specedit) {
389         st = xmalloc(sizeof(*st));
390         st->st_t = NULL;
391         st->st_nalloc = 0;
392         st->st_ntags = 0;
393     }
394     return st;
395 }
396
397 /**
398  */
399 static inline spectags freeSt(spectags st)
400 {
401     int i;
402     if (st == NULL) return NULL;
403     for (i = 0; i < st->st_ntags; i++) {
404         spectag t = st->st_t + i;
405         t->t_lang = _free(t->t_lang);
406         t->t_msgid = _free(t->t_msgid);
407     }
408     st->st_t = _free(st->st_t);
409     return _free(st);
410 }
411
412 rpmSpec newSpec(void)
413 {
414     rpmSpec spec = xcalloc(1, sizeof(*spec));
415     
416     spec->specFile = 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->check = NULL;
436     spec->clean = NULL;
437
438     spec->sources = NULL;
439     spec->packages = NULL;
440     spec->noSource = 0;
441     spec->numSources = 0;
442
443     spec->sourceRpmName = NULL;
444     spec->sourcePkgId = NULL;
445     spec->sourceHeader = NULL;
446     spec->sourceCpioList = NULL;
447     
448     spec->gotBuildRootURL = 0;
449     spec->buildRootURL = NULL;
450     spec->buildSubdir = NULL;
451
452     spec->passPhrase = NULL;
453     spec->timeCheck = 0;
454     spec->cookie = NULL;
455
456     spec->buildRestrictions = headerNew();
457     spec->BANames = NULL;
458     spec->BACount = 0;
459     spec->recursing = 0;
460     spec->BASpecs = NULL;
461
462     spec->force = 0;
463     spec->anyarch = 0;
464
465     spec->macros = rpmGlobalMacroContext;
466     
467 #ifdef WITH_LUA
468     {
469     /* make sure patches and sources tables always exist */
470     rpmlua lua = NULL; /* global state */
471     rpmluaPushTable(lua, "patches");
472     rpmluaPushTable(lua, "sources");
473     rpmluaPop(lua);
474     rpmluaPop(lua);
475     }
476 #endif
477     return spec;
478 }
479
480 rpmSpec freeSpec(rpmSpec spec)
481 {
482     struct ReadLevelEntry *rl;
483
484     if (spec == NULL) return NULL;
485
486     spec->sl = freeSl(spec->sl);
487     spec->st = freeSt(spec->st);
488
489     spec->prep = freeStringBuf(spec->prep);
490     spec->build = freeStringBuf(spec->build);
491     spec->install = freeStringBuf(spec->install);
492     spec->check = freeStringBuf(spec->check);
493     spec->clean = freeStringBuf(spec->clean);
494
495     spec->buildRootURL = _free(spec->buildRootURL);
496     spec->buildSubdir = _free(spec->buildSubdir);
497     spec->rootURL = _free(spec->rootURL);
498     spec->specFile = _free(spec->specFile);
499
500     closeSpec(spec);
501
502     while (spec->readStack) {
503         rl = spec->readStack;
504         spec->readStack = rl->next;
505         rl->next = NULL;
506         rl = _free(rl);
507     }
508     
509     spec->sourceRpmName = _free(spec->sourceRpmName);
510     spec->sourcePkgId = _free(spec->sourcePkgId);
511     spec->sourceHeader = headerFree(spec->sourceHeader);
512
513     if (spec->sourceCpioList) {
514         rpmfi fi = spec->sourceCpioList;
515         spec->sourceCpioList = NULL;
516         fi = rpmfiFree(fi);
517     }
518     
519     spec->buildRestrictions = headerFree(spec->buildRestrictions);
520
521     if (!spec->recursing) {
522         if (spec->BASpecs != NULL)
523         while (spec->BACount--) {
524             spec->BASpecs[spec->BACount] =
525                         freeSpec(spec->BASpecs[spec->BACount]);
526         }
527         spec->BASpecs = _free(spec->BASpecs);
528     }
529     spec->BANames = _free(spec->BANames);
530
531     spec->passPhrase = _free(spec->passPhrase);
532     spec->cookie = _free(spec->cookie);
533
534 #ifdef WITH_LUA
535     rpmlua lua = NULL; /* global state */
536     rpmluaDelVar(lua, "patches");
537     rpmluaDelVar(lua, "sources");       
538 #endif
539
540     spec->sources = freeSources(spec->sources);
541     spec->packages = freePackages(spec->packages);
542     
543     spec = _free(spec);
544
545     return spec;
546 }
547
548 struct OpenFileInfo * newOpenFileInfo(void)
549 {
550     struct OpenFileInfo *ofi;
551
552     ofi = xmalloc(sizeof(*ofi));
553     ofi->fd = NULL;
554     ofi->fileName = NULL;
555     ofi->lineNum = 0;
556     ofi->readBuf[0] = '\0';
557     ofi->readPtr = NULL;
558     ofi->next = NULL;
559
560     return ofi;
561 }
562
563 /**
564  * Print copy of spec file, filling in Group/Description/Summary from specspo.
565  * @param spec          spec file control structure
566  */
567 static void
568 printNewSpecfile(rpmSpec spec)
569 {
570     Header h;
571     speclines sl = spec->sl;
572     spectags st = spec->st;
573     char * msgstr = NULL;
574     int i, j;
575
576     if (sl == NULL || st == NULL)
577         return;
578
579     for (i = 0; i < st->st_ntags; i++) {
580         spectag t = st->st_t + i;
581         const char * tn = rpmTagGetName(t->t_tag);
582         const char * errstr;
583         char fmt[1024];
584
585         fmt[0] = '\0';
586         if (t->t_msgid == NULL)
587             h = spec->packages->header;
588         else {
589             Package pkg;
590             char *fe;
591
592             strcpy(fmt, t->t_msgid);
593             for (fe = fmt; *fe && *fe != '('; fe++)
594                 {} ;
595             if (*fe == '(') *fe = '\0';
596             h = NULL;
597             for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
598                 const char *pkgname;
599                 h = pkg->header;
600                 (void) headerNVR(h, &pkgname, NULL, NULL);
601                 if (!strcmp(pkgname, fmt))
602                     break;
603             }
604             if (pkg == NULL || h == NULL)
605                 h = spec->packages->header;
606         }
607
608         if (h == NULL)
609             continue;
610
611         fmt[0] = '\0';
612         (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tn), "}");
613         msgstr = _free(msgstr);
614
615         /* XXX this should use queryHeader(), but prints out tn as well. */
616         msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
617         if (msgstr == NULL) {
618             rpmlog(RPMLOG_ERR, _("can't query %s: %s\n"), tn, errstr);
619             return;
620         }
621
622         switch(t->t_tag) {
623         case RPMTAG_SUMMARY:
624         case RPMTAG_GROUP:
625             sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
626             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
627                 continue;
628             {   char *buf = xmalloc(strlen(tn) + sizeof(": ") + strlen(msgstr));
629                 (void) stpcpy( stpcpy( stpcpy(buf, tn), ": "), msgstr);
630                 sl->sl_lines[t->t_startx] = buf;
631             }
632             break;
633         case RPMTAG_DESCRIPTION:
634             for (j = 1; j < t->t_nlines; j++) {
635                 if (*sl->sl_lines[t->t_startx + j] == '%')
636                     continue;
637                 sl->sl_lines[t->t_startx + j] =
638                         _free(sl->sl_lines[t->t_startx + j]);
639             }
640             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
641                 sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
642                 continue;
643             }
644             sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
645             if (t->t_nlines > 2)
646                 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
647             break;
648         }
649     }
650     msgstr = _free(msgstr);
651
652     for (i = 0; i < sl->sl_nlines; i++) {
653         const char * s = sl->sl_lines[i];
654         if (s == NULL)
655             continue;
656         printf("%s", s);
657         if (strchr(s, '\n') == NULL && s[strlen(s)-1] != '\n')
658             printf("\n");
659     }
660 }
661
662 int rpmspecQuery(rpmts ts, QVA_t qva, const char * arg)
663 {
664     rpmSpec spec = NULL;
665     Package pkg;
666     char * buildRoot = NULL;
667     int recursing = 0;
668     char * passPhrase = "";
669     char *cookie = NULL;
670     int anyarch = 1;
671     int force = 1;
672     int res = 1;
673     int xx;
674
675     if (qva->qva_showPackage == NULL)
676         goto exit;
677
678     /* FIX: make spec abstract */
679     if (parseSpec(ts, arg, "/", buildRoot, recursing, passPhrase,
680                 cookie, anyarch, force)
681       || (spec = rpmtsSetSpec(ts, NULL)) == NULL)
682     {
683         rpmlog(RPMLOG_ERR,
684                         _("query of specfile %s failed, can't parse\n"), arg);
685         goto exit;
686     }
687
688     res = 0;
689     if (specedit) {
690         printNewSpecfile(spec);
691         goto exit;
692     }
693
694     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next)
695         xx = qva->qva_showPackage(qva, ts, pkg->header);
696
697 exit:
698     spec = freeSpec(spec);
699     return res;
700 }