rpm 5.3.7

build/spec.c

Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #include <rpmio.h>
00009 #include <rpmiotypes.h>
00010 #include <rpmlog.h>
00011 #include <rpmpgp.h>
00012 
00013 #include "buildio.h"
00014 #include "rpmds.h"
00015 #include "rpmfi.h"
00016 #include "rpmts.h"
00017 
00018 #include "rpmlua.h"
00019 
00020 #include "debug.h"
00021 
00022 /*@unchecked@*/
00023 int _pkg_debug;
00024 
00025 /*@unchecked@*/
00026 int _spec_debug;
00027 
00028 /*@-redecl@*/
00029 extern int specedit;
00030 /*@=redecl@*/
00031 
00032 #define SKIPWHITE(_x)   {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
00033 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
00034 
00035 /*@access rpmluav @*/
00036 
00041 static inline
00042 /*@null@*/ struct TriggerFileEntry * freeTriggerFiles(/*@only@*/ /*@null@*/ struct TriggerFileEntry * p)
00043         /*@modifies p @*/
00044 {
00045     struct TriggerFileEntry *o, *q = p;
00046     
00047     while (q != NULL) {
00048         o = q;
00049         q = q->next;
00050         o->fileName = _free(o->fileName);
00051         o->script = _free(o->script);
00052         o->prog = _free(o->prog);
00053         o = _free(o);
00054     }
00055     return NULL;
00056 }
00057 
00063 static inline
00064 /*@null@*/ struct Source * freeSources(/*@only@*/ /*@null@*/ struct Source * s)
00065         /*@modifies s @*/
00066 {
00067     struct Source *r, *t = s;
00068 
00069     while (t != NULL) {
00070         r = t;
00071         t = t->next;
00072         r->fullSource = _free(r->fullSource);
00073         r = _free(r);
00074     }
00075     return NULL;
00076 }
00077 
00078 rpmRC lookupPackage(Spec spec, const char *name, int flag, /*@out@*/Package *pkgp)
00079 {
00080     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00081     char *NV = NULL;
00082     char *N = NULL;
00083     char *V = NULL;
00084     Package p;
00085     Package lastp = spec->packages;
00086     rpmRC rc = RPMRC_OK;
00087     int xx;
00088     
00089     if (lastp == NULL)  /* XXX segfault avoidance */
00090         goto exit;
00091     /* "main" package */
00092     if (name == NULL)
00093         goto exit;
00094 
00095     /* Construct package name */
00096     if (flag == PART_SUBNAME) {
00097         he->tag = RPMTAG_NAME;
00098         xx = headerGet(spec->packages->header, he, 0);
00099 assert(xx != 0 && he->p.str != NULL);
00100         N = rpmExpand(he->p.str, "-", name, NULL);
00101         he->p.ptr = _free(he->p.ptr);
00102     } else {
00103         N = xstrdup(name);
00104         /* XXX restrict V to leading digit to prevent NV split ambiguity. */
00105         if ((V = strrchr(N, '-')) != NULL && xisdigit(V[1])) {
00106             NV = xstrdup(N);
00107             *V++ = '\0';
00108         } else
00109             V = NULL;
00110     }
00111 
00112     /* Match last package with same N or same {N,V} */
00113     lastp = NULL;
00114     for (p = spec->packages; p != NULL; p = p->next) {
00115         char *nv, *n, *v;
00116         nv = n = v = NULL;
00117         he->tag = RPMTAG_NAME;
00118         xx = headerGet(p->header, he, 0);
00119         if (xx && he->p.str != NULL) {
00120             n = (char *) he->p.str;
00121             he->p.str = NULL;
00122         }
00123         if (NV != NULL) {
00124             he->tag = RPMTAG_VERSION;
00125             xx = headerGet(p->header, he, 0);
00126             if (xx && he->p.str != NULL) {
00127                 v = (char *) he->p.str;
00128                 he->p.str = NULL;
00129                 nv = rpmExpand(n, "-", v, NULL);
00130             }
00131         }
00132 
00133         if (NV == NULL) {
00134             if (!strcmp(N, n))
00135                 lastp = p;
00136         } else {
00137             if (!strcmp(NV, nv) || !strcmp(NV, n)
00138             || (!strcmp(N, n) && (V == NULL || !strcmp(V, v))))
00139                 lastp = p;
00140         }
00141 /*@-usereleased@*/
00142         n = _free(n);
00143         v = _free(v);
00144         nv = _free(nv);
00145 /*@=usereleased@*/
00146     }
00147     rc = (lastp == NULL ? RPMRC_FAIL : RPMRC_OK);
00148     NV = _free(NV);
00149     N = _free(N);
00150 
00151 exit:
00152     if (pkgp)
00153         /*@-dependenttrans@*/ *pkgp = lastp; /*@=dependenttrans@*/
00154     return rc;
00155 }
00156 
00157 static void pkgFini(void * _pkg)
00158         /*@modifies _pkg @*/
00159 {
00160     Package pkg = _pkg;
00161 
00162     if (pkg == NULL) return;    /* XXX assert? */
00163     
00164     pkg->preInFile = _free(pkg->preInFile);
00165     pkg->postInFile = _free(pkg->postInFile);
00166     pkg->preUnFile = _free(pkg->preUnFile);
00167     pkg->postUnFile = _free(pkg->postUnFile);
00168     pkg->verifyFile = _free(pkg->verifyFile);
00169     pkg->sanityCheckFile = _free(pkg->sanityCheckFile);
00170 
00171     (void)headerFree(pkg->header);
00172     pkg->header = NULL;
00173     (void)rpmdsFree(pkg->ds);
00174     pkg->ds = NULL;
00175     pkg->fileList = rpmiobFree(pkg->fileList);
00176     pkg->fileFile = _free(pkg->fileFile);
00177     if (pkg->fi != NULL) {
00178         rpmfi fi = pkg->fi;
00179         pkg->fi = NULL;
00180         fi = rpmfiFree(fi);
00181     }
00182 
00183     pkg->specialDoc = rpmiobFree(pkg->specialDoc);
00184     pkg->triggerFiles = freeTriggerFiles(pkg->triggerFiles);
00185 }
00186 
00187 /*@unchecked@*/ /*@only@*/ /*@null@*/
00188 rpmioPool _pkgPool;
00189 
00190 static Package pkgGetPool(rpmioPool pool)
00191 {
00192     Package pkg;
00193 
00194     if (_pkgPool == NULL) {
00195         _pkgPool = rpmioNewPool("pkg", sizeof(*pkg), -1, _pkg_debug,
00196                         NULL, NULL, pkgFini);
00197         pool = _pkgPool;
00198     }
00199     pkg = (Package) rpmioGetPool(pool, sizeof(*pkg));
00200     memset(((char *)pkg)+sizeof(pkg->_item), 0, sizeof(*pkg)-sizeof(pkg->_item));
00201     return pkg;
00202 }
00203 
00204 Package newPackage(/*@unused@*/ Spec spec)
00205 {
00206     Package pkg = pkgGetPool(_pkgPool);
00207 
00208     pkg->header = headerNew();
00209     pkg->ds = NULL;
00210 
00211     pkg->autoProv = ((_rpmbuildFlags & 0x1) != 0);
00212     pkg->autoReq = ((_rpmbuildFlags & 0x2) != 0);
00213     
00214 #if 0    
00215     pkg->reqProv = NULL;
00216     pkg->triggers = NULL;
00217     pkg->triggerScripts = NULL;
00218 #endif
00219 
00220     pkg->triggerFiles = NULL;
00221     
00222     pkg->fileFile = NULL;
00223     pkg->fileList = NULL;
00224 
00225     pkg->fi = NULL;
00226 
00227     pkg->preInFile = NULL;
00228     pkg->postInFile = NULL;
00229     pkg->preUnFile = NULL;
00230     pkg->postUnFile = NULL;
00231     pkg->verifyFile = NULL;
00232     pkg->sanityCheckFile = NULL;
00233 
00234     pkg->specialDoc = NULL;
00235 
00236     pkg->next = NULL;
00237 
00238     return (Package)rpmioLinkPoolItem((rpmioItem)pkg, __FUNCTION__, __FILE__, __LINE__);
00239 }
00240 
00241 Package freePackages(Package packages)
00242 {
00243     Package p;
00244 
00245     while ((p = packages) != NULL) {
00246         packages = p->next;
00247         p->next = NULL;
00248         p = freePackage(p);
00249     }
00250     return NULL;
00251 }
00252 
00255 static inline /*@owned@*/ struct Source *findSource(Spec spec, rpmuint32_t num, int flag)
00256         /*@*/
00257 {
00258     struct Source *p;
00259 
00260     for (p = spec->sources; p != NULL; p = p->next)
00261         if ((num == p->num) && (p->flags & flag)) return p;
00262 
00263     return NULL;
00264 }
00265 
00268 int SpecSourceCount(Spec spec)
00269 {
00270     return spec->numSources;
00271 }
00272 
00275 SpecSource getSource(Spec spec, int num)
00276     /* @ */
00277 {
00278     struct Source *p = spec->sources;
00279     int i;
00280 
00281     for (i = 0; i < num; i++)
00282         if ((p = p->next) == NULL) return NULL;
00283 
00284 /*@-usereleased@*/
00285     return p;
00286 /*@=usereleased@*/
00287 }
00288 
00291 const char * specSourceName(SpecSource source)
00292 {
00293     return source->source;
00294 }
00295 
00298 const char * specFullSourceName(SpecSource source)
00299 {
00300     return source->fullSource;
00301 }
00302 
00305 int specSourceNum(SpecSource source)
00306 {
00307     return source->num;
00308 }
00309 
00312 int specSourceFlags(SpecSource source)
00313 {
00314     return source->flags;
00315 }
00316 
00317 int parseNoSource(Spec spec, const char * field, rpmTag tag)
00318 {
00319     const char *f, *fe;
00320     const char *name;
00321     rpmuint32_t num, flag;
00322 
00323     if (tag == RPMTAG_NOSOURCE) {
00324         flag = RPMFILE_SOURCE;
00325         name = "source";
00326     } else {
00327         flag = RPMFILE_PATCH;
00328         name = "patch";
00329     }
00330     
00331     fe = field;
00332     for (f = fe; *f != '\0'; f = fe) {
00333         struct Source *p;
00334 
00335         SKIPWHITE(f);
00336         if (*f == '\0')
00337             break;
00338         fe = f;
00339         SKIPNONWHITE(fe);
00340         if (*fe != '\0') fe++;
00341 
00342         if (parseNum(f, &num)) {
00343             rpmlog(RPMLOG_ERR, _("line %d: Bad number: %s\n"),
00344                      spec->lineNum, f);
00345             return RPMRC_FAIL;
00346         }
00347 
00348         if (! (p = findSource(spec, num, flag))) {
00349             rpmlog(RPMLOG_ERR, _("line %d: Bad no%s number: %d\n"),
00350                      spec->lineNum, name, num);
00351             return RPMRC_FAIL;
00352         }
00353 
00354         p->flags |= RPMFILE_GHOST;
00355 
00356     }
00357 
00358     return RPMRC_OK;
00359 }
00360 
00361 int addSource(Spec spec, /*@unused@*/ Package pkg,
00362                 const char *field, rpmTag tag)
00363 {
00364     struct Source *p;
00365 #if defined(RPM_VENDOR_OPENPKG) /* regular-ordered-sources */
00366     struct Source *p_last;
00367 #endif
00368     int flag = 0;
00369     const char *name = NULL;
00370     const char *mdir = NULL;
00371     const char *fieldp = NULL;
00372     char buf[BUFSIZ];
00373     uint32_t num = 0;
00374 
00375     buf[0] = '\0';
00376     switch (tag) {
00377     case RPMTAG_SOURCE:
00378         flag = RPMFILE_SOURCE;
00379         name = "source";
00380         fieldp = spec->line + strlen(name);
00381         break;
00382     case RPMTAG_PATCH:
00383         flag = RPMFILE_PATCH;
00384         name = "patch";
00385         fieldp = spec->line + strlen(name);
00386         break;
00387     case RPMTAG_ICON:
00388         flag = RPMFILE_ICON;
00389         name = "icon";
00390         fieldp = NULL;
00391         break;
00392     default:
00393 assert(0);
00394         /*@notreached@*/ break;
00395     }
00396 #if !defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
00397     mdir = getSourceDir(flag);
00398 assert(mdir != NULL);
00399 #endif
00400 
00401     /* Get the number */
00402     if (fieldp != NULL) {
00403         char * end = NULL;
00404 
00405         num = strtoul(fieldp, &end, 10);
00406         SKIPSPACE(end);
00407         if (*end != ':') {
00408             rpmlog(RPMLOG_ERR, _("line %d: No ':' terminator: %s\n"),
00409                          spec->lineNum, spec->line);
00410             return RPMRC_FAIL;
00411         }
00412     }
00413 
00414     /* Check whether tags of the same number haven't already been defined */
00415     for (p = spec->sources; p != NULL; p = p->next) {
00416         if ( p->num != num ) continue;
00417         if ((tag == RPMTAG_SOURCE && p->flags == RPMFILE_SOURCE) ||
00418             (tag == RPMTAG_PATCH  && p->flags == RPMFILE_PATCH)) {
00419                 rpmlog(RPMLOG_ERR, _("%s %d defined multiple times\n"), name, num);
00420                 return RPMRC_FAIL;
00421             }
00422     }
00423 
00424     /* Create the entry and link it in */
00425     p = xmalloc(sizeof(*p));
00426     p->num = num;
00427     p->fullSource = xstrdup(field);
00428     p->flags = flag;
00429     p->source = strrchr(p->fullSource, '/');
00430     if (p->source)
00431         p->source++;
00432     else
00433         p->source = p->fullSource;
00434 
00435 #if defined(RPM_VENDOR_OPENPKG) /* regular-ordered-sources */
00436     p->next = NULL;
00437     p_last = spec->sources;
00438     while (p_last != NULL && p_last->next != NULL)
00439         p_last = p_last->next;
00440     if (p_last != NULL)
00441         p_last->next = p;
00442     else
00443         spec->sources = p;
00444 #else
00445     p->next = spec->sources;
00446     spec->sources = p;
00447 #endif
00448 
00449     spec->numSources++;
00450 
00451     /* XXX FIXME: need to add ICON* macros. */
00452 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
00453     mdir = getSourceDir(flag, p->source);
00454 #endif
00455     if (tag != RPMTAG_ICON) {
00456         const char *body = rpmGenPath(NULL, mdir, p->source);
00457 
00458         sprintf(buf, "%s%d",
00459                 (flag & RPMFILE_PATCH) ? "PATCH" : "SOURCE", num);
00460         addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
00461         sprintf(buf, "%sURL%d",
00462                 (flag & RPMFILE_PATCH) ? "PATCH" : "SOURCE", num);
00463         addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
00464 #ifdef WITH_LUA
00465         if (!spec->recursing) {
00466             rpmlua lua = NULL; /* global state */
00467             const char * what = (flag & RPMFILE_PATCH) ? "patches" : "sources";
00468             rpmluav var = rpmluavNew();
00469 
00470             rpmluaPushTable(lua, what);
00471             rpmluavSetListMode(var, 1);
00472             rpmluavSetValue(var, RPMLUAV_STRING, body);
00473             rpmluaSetVar(lua, var);
00474 /*@-moduncon@*/
00475             var = (rpmluav) rpmluavFree(var);
00476 /*@=moduncon@*/
00477             rpmluaPop(lua);
00478         }
00479 #endif
00480         body = _free(body);
00481     }
00482     
00483     return RPMRC_OK;
00484 }
00485 
00488 static inline /*@only@*/ /*@null@*/ speclines newSl(void)
00489         /*@*/
00490 {
00491     speclines sl = NULL;
00492     if (specedit) {
00493         sl = xmalloc(sizeof(*sl));
00494         sl->sl_lines = NULL;
00495         sl->sl_nalloc = 0;
00496         sl->sl_nlines = 0;
00497     }
00498     return sl;
00499 }
00500 
00503 static inline /*@null@*/ speclines freeSl(/*@only@*/ /*@null@*/ speclines sl)
00504         /*@modifies sl @*/
00505 {
00506     int i;
00507     if (sl == NULL) return NULL;
00508     for (i = 0; i < sl->sl_nlines; i++)
00509         /*@-unqualifiedtrans@*/
00510         sl->sl_lines[i] = _free(sl->sl_lines[i]);
00511         /*@=unqualifiedtrans@*/
00512     sl->sl_lines = _free(sl->sl_lines);
00513     return _free(sl);
00514 }
00515 
00518 static inline /*@only@*/ /*@null@*/ spectags newSt(void)
00519         /*@*/
00520 {
00521     spectags st = NULL;
00522     if (specedit) {
00523         st = xmalloc(sizeof(*st));
00524         st->st_t = NULL;
00525         st->st_nalloc = 0;
00526         st->st_ntags = 0;
00527     }
00528     return st;
00529 }
00530 
00533 static inline /*@null@*/ spectags freeSt(/*@only@*/ /*@null@*/ spectags st)
00534         /*@modifies st @*/
00535 {
00536     int i;
00537     if (st == NULL) return NULL;
00538     for (i = 0; i < st->st_ntags; i++) {
00539         spectag t = st->st_t + i;
00540         t->t_lang = _free(t->t_lang);
00541         t->t_msgid = _free(t->t_msgid);
00542     }
00543     st->st_t = _free(st->st_t);
00544     return _free(st);
00545 }
00546 
00547 static void specFini(void * _spec)
00548         /*@modifies _spec @*/
00549 {
00550     Spec spec = _spec;
00551     struct ReadLevelEntry *rl;
00552 
00553     if (spec == NULL) return;   /* XXX assert? */
00554 
00555     spec->lbuf = _free(spec->lbuf);
00556 
00557     spec->sl = freeSl(spec->sl);
00558     spec->st = freeSt(spec->st);
00559 
00560     spec->prep = rpmiobFree(spec->prep);
00561     spec->build = rpmiobFree(spec->build);
00562     spec->install = rpmiobFree(spec->install);
00563     spec->check = rpmiobFree(spec->check);
00564     spec->clean = rpmiobFree(spec->clean);
00565     spec->foo = tagStoreFree(spec->foo, spec->nfoo);
00566     spec->nfoo = 0;
00567 
00568     spec->buildSubdir = _free(spec->buildSubdir);
00569     spec->rootURL = _free(spec->rootURL);
00570     spec->specFile = _free(spec->specFile);
00571 
00572     closeSpec(spec);
00573 
00574     while (spec->readStack) {
00575         rl = spec->readStack;
00576         /*@-dependenttrans@*/
00577         spec->readStack = rl->next;
00578         /*@=dependenttrans@*/
00579         rl->next = NULL;
00580         rl = _free(rl);
00581     }
00582     
00583     spec->sourceRpmName = _free(spec->sourceRpmName);
00584     spec->sourcePkgId = _free(spec->sourcePkgId);
00585     spec->sourceHeader = headerFree(spec->sourceHeader);
00586 
00587     if (spec->fi != NULL) {
00588         rpmfi fi = spec->fi;
00589         spec->fi = NULL;
00590         fi = rpmfiFree(fi);
00591     }
00592     
00593     if (!spec->recursing) {
00594         if (spec->BASpecs != NULL)
00595         while (spec->BACount--) {
00596             /*@-unqualifiedtrans@*/
00597             spec->BASpecs[spec->BACount] =
00598                         freeSpec(spec->BASpecs[spec->BACount]);
00599             /*@=unqualifiedtrans@*/
00600         }
00601         /*@-compdef@*/
00602         spec->BASpecs = _free(spec->BASpecs);
00603         /*@=compdef@*/
00604     }
00605     spec->BANames = _free(spec->BANames);
00606 
00607     spec->passPhrase = _free(spec->passPhrase);
00608     spec->cookie = _free(spec->cookie);
00609 
00610 #ifdef WITH_LUA
00611     {   rpmlua lua = NULL; /* global state */
00612         rpmluaDelVar(lua, "patches");
00613         rpmluaDelVar(lua, "sources");   
00614     }
00615 #endif
00616 
00617     spec->sources = freeSources(spec->sources);
00618 
00619     spec->dig = pgpDigFree(spec->dig);
00620     spec->packages = freePackages(spec->packages);
00621     
00622 }
00623 
00624 /*@unchecked@*/ /*@only@*/ /*@null@*/
00625 rpmioPool _specPool;
00626 
00627 static Spec specGetPool(rpmioPool pool)
00628 {
00629     Spec spec;
00630 
00631     if (_specPool == NULL) {
00632         _specPool = rpmioNewPool("spec", sizeof(*spec), -1, _spec_debug,
00633                         NULL, NULL, specFini);
00634         pool = _specPool;
00635     }
00636     spec = (Spec) rpmioGetPool(pool, sizeof(*spec));
00637     memset(((char *)spec)+sizeof(spec->_item), 0, sizeof(*spec)-sizeof(spec->_item));
00638     return spec;
00639 }
00640 
00641 Spec newSpec(void)
00642 {
00643     static const char _spec_line_buffer_size[] =
00644         "%{?_spec_line_buffer_size}%{!?_spec_line_buffer_size:100000}";
00645     Spec spec = specGetPool(_specPool);
00646     
00647     spec->specFile = NULL;
00648 
00649     spec->sl = newSl();
00650     spec->st = newSt();
00651 
00652     spec->fileStack = NULL;
00653     spec->lbuf_len = (size_t)rpmExpandNumeric(_spec_line_buffer_size);
00654     spec->lbuf = (char *)xmalloc(spec->lbuf_len);
00655     spec->lbuf[0] = '\0';
00656     spec->line = spec->lbuf;
00657     spec->nextline = NULL;
00658     spec->nextpeekc = '\0';
00659     spec->lineNum = 0;
00660     spec->readStack = xmalloc(sizeof(*spec->readStack));
00661     spec->readStack->next = NULL;
00662     spec->readStack->reading = 1;
00663 
00664     spec->rootURL = NULL;
00665 
00666     memset(&spec->sstates, 0, sizeof(spec->sstates));
00667     memset(&spec->smetrics, 0, sizeof(spec->smetrics));
00668 
00669     spec->prep = NULL;
00670     spec->build = NULL;
00671     spec->install = NULL;
00672     spec->check = NULL;
00673     spec->clean = NULL;
00674     spec->foo = NULL;
00675     spec->nfoo = 0;
00676 
00677     spec->dig = NULL;
00678 
00679     spec->sources = NULL;
00680     spec->packages = NULL;
00681     spec->noSource = 0;
00682     spec->numSources = 0;
00683 
00684     spec->sourceRpmName = NULL;
00685     spec->sourcePkgId = NULL;
00686     spec->sourceHeader = headerNew();
00687     spec->fi = NULL;
00688     
00689     spec->buildSubdir = NULL;
00690 
00691     spec->passPhrase = NULL;
00692     spec->timeCheck = 0;
00693     spec->cookie = NULL;
00694 
00695     spec->BANames = NULL;
00696     spec->BACount = 0;
00697     spec->recursing = 0;
00698     spec->toplevel = 1;
00699     spec->BASpecs = NULL;
00700 
00701     spec->force = 0;
00702     spec->anyarch = 0;
00703 
00704 /*@i@*/ spec->macros = rpmGlobalMacroContext;
00705 
00706     spec->_parseRCPOT = parseRCPOT;     /* XXX hack around backward linkage. */
00707     
00708     return (Spec)rpmioLinkPoolItem((rpmioItem)spec, __FUNCTION__, __FILE__, __LINE__);
00709 }
00710 
00711 /*@only@*/
00712 struct OpenFileInfo * newOpenFileInfo(void)
00713 {
00714     struct OpenFileInfo *ofi;
00715 
00716     ofi = xmalloc(sizeof(*ofi));
00717     ofi->fd = NULL;
00718     ofi->fileName = NULL;
00719     ofi->lineNum = 0;
00720     ofi->readBuf[0] = '\0';
00721     ofi->readPtr = NULL;
00722     ofi->next = NULL;
00723 
00724     return ofi;
00725 }
00726 
00731 static void
00732 printNewSpecfile(Spec spec)
00733         /*@globals fileSystem, internalState @*/
00734         /*@modifies spec->sl->sl_lines[], spec->packages->header,
00735                 fileSystem, internalState @*/
00736 {
00737     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00738     Header h;
00739     speclines sl = spec->sl;
00740     spectags st = spec->st;
00741     const char * msgstr = NULL;
00742     int i, j;
00743     int xx;
00744 
00745     if (sl == NULL || st == NULL)
00746         return;
00747 
00748     for (i = 0; i < st->st_ntags; i++) {
00749         spectag t = st->st_t + i;
00750         const char * tn = tagName(t->t_tag);
00751         const char * errstr;
00752         char fmt[1024];
00753 
00754         fmt[0] = '\0';
00755         if (t->t_msgid == NULL)
00756             h = spec->packages->header;
00757         else {
00758             Package pkg;
00759             char *fe;
00760 
00761             strcpy(fmt, t->t_msgid);
00762             for (fe = fmt; *fe && *fe != '('; fe++)
00763                 {} ;
00764             if (*fe == '(') *fe = '\0';
00765             h = NULL;
00766             for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
00767                 h = pkg->header;
00768                 he->tag = RPMTAG_NAME;
00769                 xx = headerGet(h, he, 0);
00770                 if (!strcmp(he->p.str, fmt)) {
00771                     he->p.ptr = _free(he->p.ptr);
00772                     /*@innerbreak@*/ break;
00773                 }
00774                 he->p.ptr = _free(he->p.ptr);
00775             }
00776             if (pkg == NULL || h == NULL)
00777                 h = spec->packages->header;
00778         }
00779 
00780         if (h == NULL)
00781             continue;
00782 
00783         fmt[0] = '\0';
00784         (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tn), "}");
00785         msgstr = _free(msgstr);
00786 
00787         /* XXX this should use queryHeader(), but prints out tn as well. */
00788         msgstr = headerSprintf(h, fmt, NULL, rpmHeaderFormats, &errstr);
00789         if (msgstr == NULL) {
00790             rpmlog(RPMLOG_ERR, _("can't query %s: %s\n"), tn, errstr);
00791             return;
00792         }
00793 
00794         switch(t->t_tag) {
00795         case RPMTAG_SUMMARY:
00796         case RPMTAG_GROUP:
00797             /*@-unqualifiedtrans@*/
00798             sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
00799             /*@=unqualifiedtrans@*/
00800             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
00801                 continue;
00802             {   char *buf = xmalloc(strlen(tn) + sizeof(": ") + strlen(msgstr));
00803                 (void) stpcpy( stpcpy( stpcpy(buf, tn), ": "), msgstr);
00804                 sl->sl_lines[t->t_startx] = buf;
00805             }
00806             /*@switchbreak@*/ break;
00807         case RPMTAG_DESCRIPTION:
00808             for (j = 1; j < t->t_nlines; j++) {
00809                 if (*sl->sl_lines[t->t_startx + j] == '%')
00810                     /*@innercontinue@*/ continue;
00811                 /*@-unqualifiedtrans@*/
00812                 sl->sl_lines[t->t_startx + j] =
00813                         _free(sl->sl_lines[t->t_startx + j]);
00814                 /*@=unqualifiedtrans@*/
00815             }
00816             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
00817                 sl->sl_lines[t->t_startx] = _free(sl->sl_lines[t->t_startx]);
00818                 continue;
00819             }
00820             sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
00821             if (t->t_nlines > 2)
00822                 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
00823             /*@switchbreak@*/ break;
00824         }
00825     }
00826     msgstr = _free(msgstr);
00827 
00828     for (i = 0; i < sl->sl_nlines; i++) {
00829         const char * s = sl->sl_lines[i];
00830         if (s == NULL)
00831             continue;
00832         printf("%s", s);
00833         if (strchr(s, '\n') == NULL && s[strlen(s)-1] != '\n')
00834             printf("\n");
00835     }
00836 }
00837 
00846 static int initSourceHeaderScriptlet(Header h,
00847                 rpmTag progTag, rpmTag scriptTag, rpmiob iob)
00848         /*@modifies h @*/
00849 {
00850     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00851     int xx;
00852 
00853     if (progTag !=(rpmTag) 0) {
00854         static const char prog[] = "/bin/sh";   /* XXX FIXME */
00855         he->tag = progTag;
00856         he->t = RPM_STRING_TYPE;
00857         he->p.str = prog;
00858         he->c = 1;
00859         xx = headerPut(h, he, 0);
00860     }
00861 
00862     if (scriptTag != (rpmTag)0 && iob != NULL) {
00863         he->tag = scriptTag;
00864         he->t = RPM_STRING_TYPE;
00865         he->p.str = rpmiobStr(iob);
00866         he->c = 1;
00867         xx = headerPut(h, he, 0);
00868     }
00869     return 0;
00870 }
00871 
00877 static int initSourceHeaderScriptlets(Spec spec)
00878         /*@modifies spec->sourceHeader @*/
00879 {
00880     int xx;
00881 
00882     if (spec->prep != NULL)
00883         xx = initSourceHeaderScriptlet(spec->sourceHeader,
00884             tagValue("Buildprepprog"), tagValue("Buildprep"), spec->prep);
00885     if (spec->build != NULL)
00886         xx = initSourceHeaderScriptlet(spec->sourceHeader,
00887             tagValue("Buildbuildprog"), tagValue("Buildbuild"), spec->build);
00888     if (spec->install != NULL)
00889         xx = initSourceHeaderScriptlet(spec->sourceHeader,
00890             tagValue("Buildinstallprog"), tagValue("Buildinstall"), spec->install);
00891     if (spec->check != NULL)
00892         xx = initSourceHeaderScriptlet(spec->sourceHeader,
00893             tagValue("Buildcheckprog"), tagValue("Buildcheck"), spec->check);
00894     if (spec->clean != NULL)
00895         xx = initSourceHeaderScriptlet(spec->sourceHeader,
00896             tagValue("Buildcleanprog"), tagValue("Buildclean"), spec->clean);
00897 
00898    return 0;
00899 }
00900 
00909 static int _specQuery(rpmts ts, QVA_t qva, const char *specName,
00910                 /*@null@*/ const char *target) 
00911         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00912         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
00913 {
00914     Spec spec = NULL;
00915     Package pkg;
00916     int res = 1;        /* assume error */
00917     int anyarch = (target == NULL) ? 1 : 0;
00918     char * passPhrase = "";
00919     int recursing = 0;
00920     char *cookie = NULL;
00921     int verify = 0;
00922     int xx;
00923 
00924     /*@-mods@*/ /* FIX: make spec abstract */
00925     if (parseSpec(ts, specName, "/", recursing, passPhrase,
00926                 cookie, anyarch, 1, verify)
00927       || (spec = rpmtsSetSpec(ts, NULL)) == NULL)
00928     {
00929         rpmlog(RPMLOG_ERR,
00930             _("query of specfile %s failed, can't parse\n"), 
00931             specName);
00932         goto exit;
00933     }
00934     /*@=mods@*/
00935 
00936     res = 0;
00937     if (specedit) {
00938         printNewSpecfile(spec);
00939         goto exit;
00940     }
00941 
00942     switch (qva->qva_source) {
00943     case RPMQV_SPECSRPM:
00944         xx = initSourceHeader(spec, NULL);
00945         xx = initSourceHeaderScriptlets(spec);
00946         xx = qva->qva_showPackage(qva, ts, spec->sourceHeader);
00947         break;
00948     default:
00949     case RPMQV_SPECFILE:
00950         for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
00951             /* If no target was specified, display all packages.
00952              * Packages with empty file lists are not produced.
00953              */
00954             /* XXX DIEDIEDIE: this logic looks flawed. */
00955             if (target == NULL || pkg->fileList != NULL) 
00956                 xx = qva->qva_showPackage(qva, ts, pkg->header);
00957         }
00958         break;
00959     }
00960 
00961 exit:
00962     spec = freeSpec(spec);
00963     return res;
00964 }
00965 
00966 int rpmspecQuery(rpmts ts, QVA_t qva, const char * arg)
00967 {
00968     int res = 1;
00969     const char * targets = rpmcliTargets;
00970     char *target;
00971     const char * t;
00972     const char * te;
00973     int nqueries = 0;
00974 
00975     if (qva->qva_showPackage == NULL)
00976         goto exit;
00977 
00978     if (targets == NULL) {
00979         res = _specQuery(ts, qva, arg, NULL); 
00980         nqueries++;
00981         goto exit;
00982     }
00983 
00984     rpmlog(RPMLOG_DEBUG, 
00985         _("Query specfile for platform(s): %s\n"), targets);
00986     for (t = targets; *t != '\0'; t = te) {
00987         /* Parse out next target platform. */ 
00988         if ((te = strchr(t, ',')) == NULL)
00989             te = t + strlen(t);
00990         target = alloca(te-t+1);
00991         strncpy(target, t, (te-t));
00992         target[te-t] = '\0';
00993         if (*te != '\0')
00994             te++;
00995 
00996         /* Query spec for this target platform. */
00997         rpmlog(RPMLOG_DEBUG, _("    target platform: %s\n"), target);
00998         /* Read in configuration for target. */
00999         if (t != targets) {
01000             rpmFreeMacros(NULL);
01001             rpmFreeRpmrc();
01002             (void) rpmReadConfigFiles(NULL, target);
01003         }
01004         res = _specQuery(ts, qva, arg, target); 
01005         nqueries++;
01006         if (res) break; 
01007     }
01008     
01009 exit:
01010     /* Restore original configuration. */
01011     if (nqueries > 1) {
01012         t = targets;
01013         if ((te = strchr(t, ',')) == NULL)
01014             te = t + strlen(t);
01015         target = alloca(te-t+1);
01016         strncpy(target, t, (te-t));
01017         target[te-t] = '\0';
01018         if (*te != '\0')
01019             te++;
01020         rpmFreeMacros(NULL);
01021         rpmFreeRpmrc();
01022         (void) rpmReadConfigFiles(NULL, target);
01023     }
01024     return res;
01025 }