home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / rpm / build / spec.c < prev    next >
C/C++ Source or Header  |  1997-09-17  |  44KB  |  1,744 lines

  1. /* RPM - Copyright (C) 1995 Red Hat Software
  2.  * 
  3.  * spec.c - routines for parsing a spec file
  4.  */
  5.  
  6. /*****************************
  7. TODO:
  8.  
  9. . should be able to drop the -n in non-%package parts
  10.  
  11. ******************************/
  12.  
  13. #include "config.h"
  14. #include "miscfn.h"
  15.  
  16. #if HAVE_ALLOCA_H
  17. # include <alloca.h>
  18. #endif
  19.  
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <sys/types.h>
  23. #include <time.h>
  24. #include <sys/time.h>
  25. #include <limits.h>
  26. #include <ctype.h>
  27.  
  28. #include "header.h"
  29. #include "spec.h"
  30. #include "specP.h"
  31. #include "messages.h"
  32. #include "rpmlib.h"
  33. #include "stringbuf.h"
  34. #include "misc.h"
  35. #include "reqprov.h"
  36. #include "trigger.h"
  37. #include "macro.h"
  38.  
  39. #define LINE_BUF_SIZE 1024
  40. #define FREE(x) { if (x) free(x); }
  41.  
  42. static struct PackageRec *new_packagerec(void);
  43. static int read_line(FILE *f, char *line);
  44. static int match_arch(char *s);
  45. static int match_os(char *s);
  46. static void free_packagerec(struct PackageRec *p);
  47. static void generateNames(Spec s);
  48. static void reset_spec(void);
  49. static int find_preamble_line(char *line, char **s);
  50. static int check_part(char *line, char **s);
  51. static int lookup_package(Spec s, struct PackageRec **pr,
  52.               char *name, int flags);
  53. static void dumpPackage(struct PackageRec *p, FILE *f);
  54.  
  55. static int dateToTimet(const char * datestr, time_t * secs);
  56. static void addChangelogEntry(Header h, int time, char *name, char *text);
  57. static int addChangelog(Header h, StringBuf sb);
  58.  
  59. static int parseProvides(struct PackageRec *p, char *line, int tag);
  60. static int parseRequiresConflicts(struct PackageRec *p, char *line,
  61.                   int flag);
  62. static void free_reqprov(struct ReqProv *p);
  63. static int noSourcePatch(Spec s, char *line, int_32 tag);
  64.  
  65. static void addListEntry(Header h, int_32 tag, char *line);
  66. static int finishCurrentPart(Spec spec, StringBuf sb,
  67.                  struct PackageRec *cur_package,
  68.                  int cur_part, char *triggerArgs,
  69.                  char *scriptProg);
  70.  
  71. Spec parseSpecAux(FILE *f, char *specfile, char *buildRootOverride,
  72.           char ***buildArchs);
  73.  
  74. /**********************************************************************/
  75. /*                                                                    */
  76. /* Source and patch structure creation/deletion/lookup                */
  77. /*                                                                    */
  78. /**********************************************************************/
  79.  
  80. static int addSource(Spec spec, char *line)
  81. {
  82.     struct sources *p;
  83.     char *s, *s1, c;
  84.     char *file;
  85.     unsigned long int x;
  86.     char name[1024], expansion[1024];
  87.  
  88.     p = malloc(sizeof(struct sources));
  89.     p->next = spec->sources;
  90.     spec->sources = p;
  91.  
  92.     if (! strncasecmp(line, "source", 6)) {
  93.     spec->numSources++;
  94.     p->ispatch = 0;
  95.     s = line + 6;
  96.     } else if (! strncasecmp(line, "patch", 5)) {
  97.     spec->numPatches++;
  98.     p->ispatch = 1;
  99.     s = line + 5;
  100.     } else {
  101.     rpmError(RPMERR_BADSPEC, "Not a source/patch line: %s\n", line);
  102.     return(RPMERR_BADSPEC);
  103.     }
  104.  
  105.     s += strspn(s, " \t\n");
  106.     p->num = 0;
  107.     if (*s != ':') {
  108.         x = strspn(s, "0123456789");
  109.     if (! x) {
  110.         rpmError(RPMERR_BADSPEC, "Bad source/patch line: %s\n", line);
  111.         return(RPMERR_BADSPEC);
  112.     }
  113.     c = s[x];
  114.     s[x] = '\0';
  115.     s1 = NULL;
  116.     p->num = strtoul(s, &s1, 10);
  117.     if ((*s1) || (s1 == s) || (p->num == ULONG_MAX)) {
  118.         s[x] = c;
  119.         rpmError(RPMERR_BADSPEC, "Bad source/patch number: %s\n", s);
  120.         return(RPMERR_BADSPEC);
  121.     }
  122.     s[x] = c;
  123.     s += x;
  124.     /* skip spaces */
  125.     s += strspn(s, " \t\n");
  126.     }
  127.  
  128.     if (*s != ':') {
  129.     rpmError(RPMERR_BADSPEC, "Bad source/patch line: %s\n", line);
  130.     return(RPMERR_BADSPEC);
  131.     }
  132.     
  133.     /* skip to actual source */
  134.     s++;
  135.     s += strspn(s, " \t\n");
  136.  
  137.     file = strtok(s, " \t\n");
  138.     if (! file) {
  139.     rpmError(RPMERR_BADSPEC, "Bad source/patch line: %s\n", line);
  140.     return(RPMERR_BADSPEC);
  141.     }
  142.     p->fullSource = strdup(file);
  143.     p->source = strrchr(p->fullSource, '/');
  144.     if (p->source) {
  145.     p->source++;
  146.     } else {
  147.     p->source = p->fullSource;
  148.     }
  149.  
  150.     sprintf(expansion, "%s/%s", rpmGetVar(RPMVAR_SOURCEDIR), p->source);
  151.     sprintf(name, "%s%d", (p->ispatch) ? "PATCH" : "SOURCE", p->num);
  152.     addMacro(name, expansion);
  153.     sprintf(name, "%sURL%d", (p->ispatch) ? "PATCH" : "SOURCE", p->num);
  154.     addMacro(name, p->fullSource);
  155.     
  156.     if (p->ispatch) {
  157.     rpmMessage(RPMMESS_DEBUG, "Patch(%d) = %s\n", p->num, p->fullSource);
  158.     } else {
  159.     rpmMessage(RPMMESS_DEBUG, "Source(%d) = %s\n", p->num, p->fullSource);
  160.     }
  161.     
  162.     return 0;
  163. }
  164.  
  165. static void freeSources(Spec s)
  166. {
  167.     struct sources *p1, *p2;
  168.  
  169.     p1 = s->sources;
  170.     while (p1) {
  171.     p2 = p1;
  172.     p1 = p1->next;
  173.     free(p2->fullSource);
  174.     free(p2);
  175.     }
  176. }
  177.  
  178. char *getSource(Spec s, int ispatch, int num)
  179. {
  180.     struct sources *p = s->sources;
  181.  
  182.     while (p) {
  183.     if ((ispatch == p->ispatch) &&
  184.         (num == p->num)) {
  185.         break;
  186.     } else {
  187.         p = p->next;
  188.     }
  189.     }
  190.  
  191.     if (p) {
  192.     return(p->source);
  193.     } else {
  194.     return(NULL);
  195.     }
  196. }
  197.  
  198. char *getFullSource(Spec s, int ispatch, int num)
  199. {
  200.     struct sources *p = s->sources;
  201.  
  202.     while (p) {
  203.     if ((ispatch == p->ispatch) &&
  204.         (num == p->num)) {
  205.         break;
  206.     } else {
  207.         p = p->next;
  208.     }
  209.     }
  210.  
  211.     if (p) {
  212.     return(p->fullSource);
  213.     } else {
  214.     return(NULL);
  215.     }
  216. }
  217.  
  218. int noSourcePatch(Spec s, char *line, int_32 tag)
  219. {
  220.     int_32 array[1024];  /* XXX - max 1024 sources or patches */
  221.     int_32 num;
  222.     int count;
  223.     char *t, *te;
  224.  
  225.     if (((tag == RPMTAG_NOSOURCE) && s->numNoSource) ||
  226.     ((tag == RPMTAG_NOPATCH) && s->numNoPatch)) {
  227.     rpmError(RPMERR_BADSPEC, "Only one nosource/nopatch line allowed\n");
  228.     return(RPMERR_BADSPEC);
  229.     }
  230.     
  231.     count = 0;
  232.     while ((t = strtok(line, ", \t"))) {
  233.     num = strtoul(t, &te, 10);
  234.     if ((*te) || (te == t) || (num == ULONG_MAX)) {
  235.         rpmError(RPMERR_BADSPEC, "Bad source/patch number: %s\n", t);
  236.         return(RPMERR_BADSPEC);
  237.     }
  238.     array[count++] = num;
  239.     rpmMessage(RPMMESS_DEBUG, "Skipping source/patch number: %d\n", num);
  240.     line = NULL;
  241.     }
  242.  
  243.     if (count) {
  244.     if (tag == RPMTAG_NOSOURCE) {
  245.         s->numNoSource = count;
  246.         s->noSource = malloc(sizeof(int_32) * count);
  247.         memcpy(s->noSource, array, sizeof(int_32) * count);
  248.     } else {
  249.         s->numNoPatch = count;
  250.         s->noPatch = malloc(sizeof(int_32) * count);
  251.         memcpy(s->noPatch, array, sizeof(int_32) * count);
  252.     }
  253.     }
  254.  
  255.     return 0;
  256. }
  257.  
  258. /**********************************************************************/
  259. /*                                                                    */
  260. /* Provide/Require handling                                           */
  261. /*                                                                    */
  262. /**********************************************************************/
  263.  
  264. static void free_reqprov(struct ReqProv *p)
  265. {
  266.     struct ReqProv *s;
  267.     
  268.     while (p) {
  269.     s = p;
  270.     p = p->next;
  271.     FREE(s->name);
  272.     FREE(s->version);
  273.     free(s);
  274.     }
  275. }
  276.  
  277. struct ReqComp ReqComparisons[] = {
  278.     { "<=", RPMSENSE_LESS | RPMSENSE_EQUAL},
  279.     { "<=S", RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_SERIAL},
  280.     { "=<", RPMSENSE_LESS | RPMSENSE_EQUAL},
  281.     { "=<S", RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_SERIAL},
  282.     { "<", RPMSENSE_LESS},
  283.     { "<S", RPMSENSE_LESS | RPMSENSE_SERIAL},
  284.  
  285.     { "=", RPMSENSE_EQUAL},
  286.     { "=S", RPMSENSE_EQUAL | RPMSENSE_SERIAL},
  287.     
  288.     { ">=", RPMSENSE_GREATER | RPMSENSE_EQUAL},
  289.     { ">=S", RPMSENSE_GREATER | RPMSENSE_EQUAL | RPMSENSE_SERIAL},
  290.     { "=>", RPMSENSE_GREATER | RPMSENSE_EQUAL},
  291.     { "=>S", RPMSENSE_GREATER | RPMSENSE_EQUAL | RPMSENSE_SERIAL},
  292.     { ">", RPMSENSE_GREATER},
  293.     { ">S", RPMSENSE_GREATER | RPMSENSE_SERIAL},
  294.     { NULL, 0 },
  295. };
  296.  
  297. static int parseRequiresConflicts(struct PackageRec *p, char *line,
  298.                   int flag)
  299. {
  300.     char *req = NULL;
  301.     char *version = NULL;
  302.     int flags;
  303.     struct ReqComp *rc;
  304.  
  305.     while (req || (req = strtok(line, " ,\t\n"))) {
  306.     switch (flag) {
  307.       case RPMTAG_CONFLICTFLAGS:
  308.         flags = RPMSENSE_CONFLICTS;
  309.         break;
  310.       case RPMTAG_PREREQ:
  311.         flags = RPMSENSE_PREREQ;
  312.         break;
  313.       default:
  314.         flags = RPMSENSE_ANY;
  315.         break;
  316.     }
  317.     if (flag == RPMTAG_CONFLICTFLAGS && req[0] == '/') {
  318.         rpmError(RPMERR_BADSPEC,
  319.              "No file names in Conflicts: %s", req);
  320.         return RPMERR_BADSPEC;
  321.     }
  322.     if ((version = strtok(NULL, " ,\t\n"))) {
  323.         rc = ReqComparisons;
  324.         while (rc->token && strcmp(version, rc->token)) {
  325.         rc++;
  326.         }
  327.         if (rc->token) {
  328.         if (req[0] == '/') {
  329.             rpmError(RPMERR_BADSPEC,
  330.                  "No versions on file names in Requires: %s", req);
  331.             return RPMERR_BADSPEC;
  332.         }
  333.         if (flag == RPMTAG_PREREQ) {
  334.             rpmError(RPMERR_BADSPEC,
  335.                  "No versions in PreReq: %s", req);
  336.             return RPMERR_BADSPEC;
  337.         }
  338.         /* read a version */
  339.         flags |= rc->flags;
  340.         version = strtok(NULL, " ,\t\n");
  341.         }
  342.     }
  343.     if ((flags & RPMSENSE_SENSEMASK) && !version) {
  344.         rpmError(RPMERR_BADSPEC, "Version required in require/conflict");
  345.         return RPMERR_BADSPEC;
  346.     }
  347.  
  348.     addReqProv(p, flags, req,
  349.            (flags & RPMSENSE_SENSEMASK) ? version : NULL);
  350.  
  351.     req = NULL;
  352.     if (! (flags & RPMSENSE_SENSEMASK)) {
  353.         /* No version -- we just read a name */
  354.         req = version;
  355.     }
  356.     line = NULL;
  357.     }
  358.     
  359.     return 0;
  360. }
  361.  
  362. static int parseProvides(struct PackageRec *p, char *line, int tag)
  363. {
  364.     char *prov;
  365.     int flags;
  366.  
  367.     flags = (tag == RPMTAG_PROVIDES) ? RPMSENSE_PROVIDES : RPMSENSE_OBSOLETES;
  368.     
  369.     while ((prov = strtok(line, " ,\t\n"))) {
  370.     if (prov[0] == '/') {
  371.         rpmError(RPMERR_BADSPEC,
  372.              "No file names in %s: %s",
  373.              (tag == RPMTAG_PROVIDES) ? "provides" : "obsoletes",
  374.              prov);
  375.         return RPMERR_BADSPEC;
  376.     }
  377.     addReqProv(p, flags, prov, NULL);
  378.     line = NULL;
  379.     }
  380.     return 0;
  381. }
  382.  
  383. /**********************************************************************/
  384. /*                                                                    */
  385. /* Spec and package structure creation/deletion/lookup                */
  386. /*                                                                    */
  387. /**********************************************************************/
  388.  
  389. static struct PackageRec *new_packagerec(void)
  390. {
  391.     struct PackageRec *p = malloc(sizeof(struct PackageRec));
  392.  
  393.     p->subname = NULL;
  394.     p->newname = NULL;
  395.     p->icon = NULL;
  396.     p->header = headerNew();
  397.     p->filelist = newStringBuf();
  398.     p->files = -1;  /* -1 means no %files, thus no package */
  399.     p->fileFile = NULL;
  400.     p->doc = newStringBuf();
  401.     p->reqprov = NULL;
  402.     p->numReq = 0;
  403.     p->numProv = 0;
  404.     p->numConflict = 0;
  405.     p->numPreReq = 0;
  406.     p->numObsoletes = 0;
  407.     p->trigger.alloced = 0;
  408.     p->trigger.used = 0;
  409.     p->trigger.triggerScripts = NULL;
  410.     p->trigger.trigger = NULL;
  411.     p->trigger.triggerCount = 0;
  412.     p->next = NULL;
  413.  
  414.     return p;
  415. }
  416.  
  417. void free_packagerec(struct PackageRec *p)
  418. {
  419.     if (! p ) return;
  420.     
  421.     headerFree(p->header);
  422.     freeStringBuf(p->filelist);
  423.     freeStringBuf(p->doc);
  424.     FREE(p->subname);
  425.     FREE(p->newname);
  426.     FREE(p->icon);
  427.     FREE(p->fileFile);
  428.     free_reqprov(p->reqprov);
  429.     freeTriggers(p->trigger);
  430.     if (p->next) {
  431.         free_packagerec(p->next);
  432.     }
  433.     free(p);
  434. }
  435.  
  436. void freeSpec(Spec s)
  437. {
  438.     FREE(s->name);
  439.     FREE(s->specfile);
  440.     FREE(s->noSource);
  441.     FREE(s->noPatch);
  442.     FREE(s->buildroot);
  443.     FREE(s->buildArch);
  444.     freeSources(s);
  445.     freeStringBuf(s->prep);
  446.     freeStringBuf(s->build);
  447.     freeStringBuf(s->install);
  448.     freeStringBuf(s->doc);
  449.     freeStringBuf(s->clean);
  450.     free_packagerec(s->packages);
  451.     free(s);
  452. }
  453.  
  454. #define LP_CREATE           1
  455. #define LP_FAIL_EXISTS     (1 << 1)
  456. #define LP_SUBNAME         (1 << 2)
  457. #define LP_NEWNAME         (1 << 3)
  458.  
  459. int lookup_package(Spec s, struct PackageRec **pr, char *name, int flags)
  460. {
  461.     struct PackageRec *package;
  462.     struct PackageRec **ppp;
  463.  
  464.     package = s->packages;
  465.     while (package) {
  466.     if (flags & LP_SUBNAME) {
  467.         if (! package->subname) {
  468.             package = package->next;
  469.             continue;
  470.         }
  471.         if (! strcmp(package->subname, name)) {
  472.         break;
  473.         }
  474.     } else if (flags & LP_NEWNAME) {
  475.         if (! package->newname) {
  476.             package = package->next;
  477.             continue;
  478.         }
  479.         if (! strcmp(package->newname, name)) {
  480.         break;
  481.         }
  482.     } else {
  483.         /* Base package */
  484.         if ((! package->newname) && (! package->subname)) {
  485.         break;
  486.         }
  487.     }
  488.     package = package->next;
  489.     }
  490.     
  491.     if (package && (flags & LP_FAIL_EXISTS)) {
  492.     return 0;
  493.     }
  494.  
  495.     if (package) {
  496.     *pr = package;
  497.     return 1;
  498.     }
  499.  
  500.     /* At this point the package does not exist */
  501.  
  502.     if (! (flags & LP_CREATE)) {
  503.     return 0;
  504.     }
  505.  
  506.     /* Create it */
  507.     package = new_packagerec();
  508.     if (name) {
  509.     if (flags & LP_SUBNAME) {
  510.         package->subname = strdup(name);
  511.     } else if (flags & LP_NEWNAME) {
  512.         package->newname = strdup(name);
  513.     }
  514.     }
  515.  
  516.     /* Link it in to the spec */
  517.     ppp = &(s->packages);
  518.     while (*ppp) {
  519.     ppp = &((*ppp)->next);
  520.     }
  521.     *ppp = package;
  522.  
  523.     *pr = package;
  524.     return 1;
  525. }
  526.  
  527. static void generateNames(Spec s)
  528. {
  529.     struct PackageRec *package;
  530.     char buf[1024];
  531.     char *name;
  532.  
  533.     package = s->packages;
  534.     while (package) {
  535.     if (package->subname) {
  536.         sprintf(buf, "%s-%s", s->name, package->subname);
  537.         name = buf;
  538.     } else if (package->newname) {
  539.         name = package->newname;
  540.     } else {
  541.         /* Must be the main package */
  542.         name = s->name;
  543.     }
  544.     headerAddEntry(package->header, RPMTAG_NAME, RPM_STRING_TYPE, name, 1);
  545.     
  546.     package = package->next;
  547.     }
  548. }
  549.  
  550. /* datestr is of the form 'Wed Jan 1 1997' */
  551. static int dateToTimet(const char * datestr, time_t * secs)
  552. {
  553.     struct tm time;
  554.     char * chptr, * end, ** idx;
  555.     char * date = strcpy(alloca(strlen(datestr) + 1), datestr);
  556.     static char * days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 
  557.                 NULL };
  558.     static char * months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  559.                  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
  560.     static char lengths[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  561.     
  562.     memset(&time, 0, sizeof(time));
  563.  
  564.     end = chptr = date;
  565.  
  566.     /* day of week */
  567.     if ((chptr = strtok(date, " \t\n")) == NULL) return -1;
  568.     idx = days;
  569.     while (*idx && strcmp(*idx, chptr)) idx++;
  570.     if (!*idx) return -1;
  571.  
  572.     /* month */
  573.     if ((chptr = strtok(NULL, " \t\n")) == NULL) return -1;
  574.     idx = months;
  575.     while (*idx && strcmp(*idx, chptr)) idx++;
  576.     if (!*idx) return -1;
  577.  
  578.     time.tm_mon = idx - months;
  579.  
  580.     /* day */
  581.     if ((chptr = strtok(NULL, " \t\n")) == NULL) return -1;
  582.  
  583.     /* make this noon so the day is always right (as we make this UTC) */
  584.     time.tm_hour = 12;
  585.  
  586.     time.tm_mday = strtol(chptr, &chptr, 10);
  587.     if (*chptr) return -1;
  588.     if (time.tm_mday < 0 || time.tm_mday > lengths[time.tm_mon]) return -1;
  589.  
  590.     /* year */
  591.     if ((chptr = strtok(NULL, " \t\n")) == NULL) return -1;
  592.  
  593.     time.tm_year = strtol(chptr, &chptr, 10);
  594.     if (*chptr) return -1;
  595.     if (time.tm_year < 1997 || time.tm_year >= 3000) return -1;
  596.     time.tm_year -= 1900;
  597.  
  598.     *secs = mktime(&time);
  599.     if (*secs == -1) return -1;
  600.  
  601.     /* adjust to GMT */
  602.     *secs += timezone;
  603.  
  604.     return 0;
  605. }
  606.  
  607. static void addChangelogEntry(Header h, int time, char *name, char *text)
  608. {
  609.     if (headerIsEntry(h, RPMTAG_CHANGELOGTIME)) {
  610.     headerAppendEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE,
  611.               &time, 1);
  612.     headerAppendEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE,
  613.               &name, 1);
  614.     headerAppendEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE,
  615.              &text, 1);
  616.     } else {
  617.     headerAddEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE,
  618.                &time, 1);
  619.     headerAddEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE,
  620.                &name, 1);
  621.     headerAddEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE,
  622.                &text, 1);
  623.     }
  624. }
  625.  
  626. static int addChangelog(Header h, StringBuf sb)
  627. {
  628.     char *s;
  629.     int i;
  630.     int time, lastTime = 0;
  631.     char *date, *name, *text, *next;
  632.  
  633.     s = getStringBuf(sb);
  634.  
  635.     /* skip space */
  636.     while (*s && isspace(*s)) s++;
  637.  
  638.     while (*s) {
  639.     if (*s != '*') {
  640.         rpmError(RPMERR_BADSPEC, "%%changelog entries must start with *");
  641.         return RPMERR_BADSPEC;
  642.     }
  643.  
  644.     /* find end of line */
  645.     date = s;
  646.     while (*s && *s != '\n') s++;
  647.     if (! *s) {
  648.         rpmError(RPMERR_BADSPEC, "incomplete %%changelog entry");
  649.         return RPMERR_BADSPEC;
  650.     }
  651.     *s = '\0';
  652.     text = s + 1;
  653.     
  654.     /* 4 fields of date */
  655.     date++;
  656.     s = date;
  657.     for (i = 0; i < 4; i++) {
  658.         while (*s && isspace(*s)) s++;
  659.         while (*s && !isspace(*s)) s++;
  660.     }
  661.     while (isspace(*date)) date++;
  662.     if (dateToTimet(date, (time_t *)&time)) {
  663.         rpmError(RPMERR_BADSPEC, "bad date in %%changelog: %s", date);
  664.         return RPMERR_BADSPEC;
  665.     }
  666.     if (lastTime && lastTime < time) {
  667.         rpmError(RPMERR_BADSPEC,
  668.              "%%changelog not in decending chronological order");
  669.         return RPMERR_BADSPEC;
  670.     }
  671.     lastTime = time;
  672.  
  673.     /* skip space to the name */
  674.     while (*s && isspace(*s)) s++;
  675.     if (! *s) {
  676.         rpmError(RPMERR_BADSPEC, "missing name in %%changelog");
  677.         return RPMERR_BADSPEC;
  678.     }
  679.  
  680.     /* name */
  681.     name = s;
  682.     while (*s) s++;
  683.     while (s > name && isspace(*s)) {
  684.         *s-- = '\0';
  685.     }
  686.     if (s == name) {
  687.         rpmError(RPMERR_BADSPEC, "missing name in %%changelog");
  688.         return RPMERR_BADSPEC;
  689.     }
  690.  
  691.     /* text */
  692.     while (*text && isspace(*text)) text++;
  693.     if (! *text) {
  694.         rpmError(RPMERR_BADSPEC, "no description in %%changelog");
  695.         return RPMERR_BADSPEC;
  696.     }
  697.         
  698.     /* find the next leading '*' (or eos) */
  699.     s = text;
  700.     do {
  701.        s++;
  702.     } while (*s && (*(s-1) != '\n' || *s != '*'));
  703.     next = s;
  704.     s--;
  705.  
  706.     /* backup to end of description */
  707.     while ((s > text) && isspace(*s)) {
  708.         *s-- = '\0';
  709.     }
  710.     
  711.     addChangelogEntry(h, time, name, text);
  712.     s = next;
  713.     }
  714.  
  715.     return 0;
  716. }
  717.  
  718. /**********************************************************************/
  719. /*                                                                    */
  720. /* Line reading                                                       */
  721. /*                                                                    */
  722. /**********************************************************************/
  723.  
  724. static int match_arch(char *s)
  725. {
  726.     char *tok, *arch;
  727.     int sense, match;
  728.  
  729.     rpmGetArchInfo(&arch, NULL);
  730.     match = 0;
  731.     
  732.     tok = strtok(s, " \n\t");
  733.     sense = (! strcmp(tok, "%ifarch")) ? 1 : 0;
  734.  
  735.     while ((tok = strtok(NULL, " \n\t"))) {
  736.     if (! strcmp(tok, arch)) {
  737.         match |= 1;
  738.     }
  739.     }
  740.  
  741.     return (sense == match);
  742. }
  743.  
  744. static int match_os(char *s)
  745. {
  746.     char *tok, *os;
  747.     int sense, match;
  748.  
  749.     rpmGetOsInfo(&os, NULL);
  750.     match = 0;
  751.     
  752.     tok = strtok(s, " \n\t");
  753.     sense = (! strcmp(tok, "%ifos")) ? 1 : 0;
  754.  
  755.     while ((tok = strtok(NULL, " \n\t"))) {
  756.     if (! strcmp(tok, os)) {
  757.         match |= 1;
  758.     }
  759.     }
  760.  
  761.     return (sense == match);
  762. }
  763.  
  764. static struct read_level_entry {
  765.     int reading;  /* 1 if we are reading at this level */
  766.     struct read_level_entry *next;
  767. } *read_level = NULL;
  768.  
  769. static int read_line(FILE *f, char *line)
  770. {
  771.     static struct read_level_entry *rl;
  772.     int gotline;
  773.     char *r;
  774.     char *firstChar;
  775.  
  776.     do {
  777.         gotline = 0;
  778.     if (! fgets(line, LINE_BUF_SIZE, f)) {
  779.         /* the end */
  780.         if (read_level->next) {
  781.         rpmError(RPMERR_UNMATCHEDIF, "Unclosed %%if");
  782.             return RPMERR_UNMATCHEDIF;
  783.         } else {
  784.             return 0;
  785.         }
  786.     }
  787.     firstChar = line;
  788.     while (*firstChar && isspace(*firstChar)) {
  789.         firstChar++;
  790.     }
  791.     if ((! strncmp("%ifarch", firstChar, 7)) ||
  792.         (! strncmp("%ifnarch", firstChar, 8))) {
  793.         expandMacros(line);
  794.         rl = malloc(sizeof(struct read_level_entry));
  795.         rl->next = read_level;
  796.         rl->reading = read_level->reading && match_arch(line);
  797.         read_level = rl;
  798.     } else if ((! strncmp("%ifos", firstChar, 5)) ||
  799.            (! strncmp("%ifnos", firstChar, 6))) {
  800.         expandMacros(line);
  801.         rl = malloc(sizeof(struct read_level_entry));
  802.         rl->next = read_level;
  803.         rl->reading = read_level->reading && match_os(line);
  804.         read_level = rl;
  805.     } else if (! strncmp("%else", firstChar, 5)) {
  806.         expandMacros(line);
  807.         if (! read_level->next) {
  808.             /* Got an else with no %if ! */
  809.         rpmError(RPMERR_UNMATCHEDIF, "Got a %%else with no if");
  810.             return RPMERR_UNMATCHEDIF;
  811.         }
  812.         read_level->reading =
  813.             read_level->next->reading && ! read_level->reading;
  814.     } else if (! strncmp("%endif", firstChar, 6)) {
  815.         expandMacros(line);
  816.         if (! read_level->next) {
  817.         rpmError(RPMERR_UNMATCHEDIF, "Got a %%endif with no if");
  818.         return RPMERR_UNMATCHEDIF;
  819.         }
  820.         rl = read_level;
  821.         read_level = rl->next;
  822.         free(rl);
  823.     } else {
  824.         if (read_level->reading) {
  825.         expandMacros(line);
  826.         }
  827.             gotline = 1;
  828.         }
  829.     } while (! (gotline && read_level->reading));
  830.     
  831.     r = line + (strlen(line)) - 1;
  832.     while (isspace(*r)) {
  833.         *(r--) = '\0';
  834.     }
  835.     return 1;
  836. }
  837.  
  838. /**********************************************************************/
  839. /*                                                                    */
  840. /* Line parsing                                                       */
  841. /*                                                                    */
  842. /**********************************************************************/
  843.  
  844. struct preamble_line {
  845.     int tag;
  846.     int len;
  847.     char *token;
  848. } preamble_spec[] = {
  849.     {RPMTAG_NAME,          0, "name"},
  850.     {RPMTAG_VERSION,       0, "version"},
  851.     {RPMTAG_RELEASE,       0, "release"},
  852.     {RPMTAG_SERIAL,        0, "serial"},
  853.     {RPMTAG_DESCRIPTION,   0, "description"},
  854.     {RPMTAG_SUMMARY,       0, "summary"},
  855.     {RPMTAG_COPYRIGHT,     0, "copyright"},
  856.     {RPMTAG_DISTRIBUTION,  0, "distribution"},
  857.     {RPMTAG_VENDOR,        0, "vendor"},
  858.     {RPMTAG_GROUP,         0, "group"},
  859.     {RPMTAG_PACKAGER,      0, "packager"},
  860.     {RPMTAG_URL,           0, "url"},
  861.     {RPMTAG_ROOT,          0, "root"},
  862.     {RPMTAG_SOURCE,        0, "source"},
  863.     {RPMTAG_PATCH,         0, "patch"},
  864.     {RPMTAG_NOSOURCE,      0, "nosource"},
  865.     {RPMTAG_NOPATCH,       0, "nopatch"},
  866.     {RPMTAG_EXCLUDEARCH,   0, "excludearch"},
  867.     {RPMTAG_EXCLUSIVEARCH, 0, "exclusivearch"},
  868.     {RPMTAG_EXCLUDEOS,     0, "excludeos"},
  869.     {RPMTAG_EXCLUSIVEOS,   0, "exclusiveos"},
  870.     {RPMTAG_EXCLUDE,       0, "exclude"},
  871.     {RPMTAG_EXCLUSIVE,     0, "exclusive"},
  872.     {RPMTAG_ICON,          0, "icon"},
  873.     {RPMTAG_PROVIDES,      0, "provides"},
  874.     {RPMTAG_REQUIREFLAGS,  0, "requires"},
  875.     {RPMTAG_PREREQ,        0, "prereq"},
  876.     {RPMTAG_CONFLICTFLAGS, 0, "conflicts"},
  877.     {RPMTAG_OBSOLETES,     0, "obsoletes"},
  878.     {RPMTAG_DEFAULTPREFIX, 0, "prefix"},
  879.     {RPMTAG_BUILDROOT,     0, "buildroot"},
  880.     {RPMTAG_BUILDARCHS,    0, "buildarchitectures"},
  881.     {RPMTAG_AUTOREQPROV,   0, "autoreqprov"},
  882.     {0, 0, 0}
  883. };
  884.  
  885. static int find_preamble_line(char *line, char **s)
  886. {
  887.     struct preamble_line *p = preamble_spec;
  888.  
  889.     while (p->token && strncasecmp(line, p->token, p->len)) {
  890.         p++;
  891.     }
  892.     if (!p->token) return 0;
  893.     *s = line + p->len;
  894.  
  895.     /* Unless this is a source or a patch, a ':' better be next */
  896.     if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
  897.     *s += strspn(*s, " \t");
  898.     if (**s != ':') {
  899.         return 0;
  900.     }
  901.     }
  902.     
  903.     *s += strspn(*s, ": \t");
  904.     return p->tag;
  905. }
  906.  
  907. /* None of these can be 0 !! */
  908. #define PREAMBLE_PART       1
  909. #define PREP_PART           2
  910. #define BUILD_PART          3
  911. #define INSTALL_PART        4
  912. #define CLEAN_PART          5
  913. #define PREIN_PART          6
  914. #define POSTIN_PART         7
  915. #define PREUN_PART          8
  916. #define POSTUN_PART         9
  917. #define FILES_PART         10
  918. #define CHANGELOG_PART     11
  919. #define DESCRIPTION_PART   12
  920. #define TRIGGERIN_PART     13
  921. #define TRIGGERUN_PART     14
  922. #define VERIFYSCRIPT_PART  15
  923.  
  924. static struct part_rec {
  925.     int part;
  926.     int len;
  927.     char *s;
  928. } part_list[] = {
  929.     {PREAMBLE_PART,    0, "%package"},
  930.     {PREP_PART,        0, "%prep"},
  931.     {BUILD_PART,       0, "%build"},
  932.     {INSTALL_PART,     0, "%install"},
  933.     {CLEAN_PART,       0, "%clean"},
  934.     {PREUN_PART,       0, "%preun"},
  935.     {POSTUN_PART,      0, "%postun"},
  936.     {PREIN_PART,       0, "%pre"},
  937.     {POSTIN_PART,      0, "%post"},
  938.     {FILES_PART,       0, "%files"},
  939.     {CHANGELOG_PART,   0, "%changelog"},
  940.     {DESCRIPTION_PART, 0, "%description"},
  941.     {TRIGGERUN_PART,   0, "%triggerun"},
  942.     {TRIGGERIN_PART,   0, "%trigger"},
  943.     {VERIFYSCRIPT_PART, 0, "%verifyscript"},
  944.     {0, 0, 0}
  945. };
  946.  
  947. static int check_part(char *line, char **s)
  948. {
  949.     struct part_rec *p = part_list;
  950.  
  951.     while (p->s && strncmp(line, p->s, p->len)) {
  952.         p++;
  953.     }
  954.     if (!p) return 0;
  955.     *s = line + p->len;
  956.     *s += strspn(*s, " \t");
  957.     if (**s == '\0') {
  958.         *s = NULL;
  959.     }
  960.     return p->part;
  961. }
  962.  
  963. #if 0
  964. static char *chop_line(char *s)
  965. {
  966.     char *p, *e;
  967.  
  968.     p = s;
  969.     p += strspn(s, " \t");
  970.     if (*p == '\0') {
  971.     return NULL;
  972.     }
  973.     e = s + strlen(s) - 1;
  974.     while (index(" \t", *e)) {
  975.     e--;
  976.     }
  977.     return p;
  978. }
  979. #endif
  980.  
  981. static void addListEntry(Header h, int_32 tag, char *line)
  982. {
  983.     int argc;
  984.     char **argv;
  985.     char **argvs;
  986.     char *s;
  987.  
  988.     argvs = argv = malloc(strlen(line) * sizeof(char *));
  989.     argc = 0;
  990.     while ((s = strtok(line, " \t"))) {
  991.     *argv = s;
  992.     argc++;
  993.     argv++;
  994.     line = NULL;
  995.     }
  996.     if (argc) {
  997.     headerAddEntry(h, tag, RPM_STRING_ARRAY_TYPE, argvs, argc);
  998.     }
  999.     free(argvs);
  1000. }
  1001.  
  1002. static int finishCurrentPart(Spec spec, StringBuf sb,
  1003.                  struct PackageRec *cur_package,
  1004.                  int cur_part, char *triggerArgs,
  1005.                  char *scriptProg)
  1006. {
  1007.     int t1 = 0;
  1008.     int t2 = 0;
  1009.  
  1010.     stripTrailingBlanksStringBuf(sb);
  1011.  
  1012.     switch (cur_part) {
  1013.       case PREIN_PART:
  1014.     t1 = RPMTAG_PREIN;
  1015.     t2 = RPMTAG_PREINPROG;
  1016.     break;
  1017.       case POSTIN_PART:
  1018.     t1 = RPMTAG_POSTIN;
  1019.     t2 = RPMTAG_POSTINPROG;
  1020.     break;
  1021.       case PREUN_PART:
  1022.     t1 = RPMTAG_PREUN;
  1023.     t2 = RPMTAG_PREUNPROG;
  1024.     break; 
  1025.       case POSTUN_PART:
  1026.     t1 = RPMTAG_POSTUN;
  1027.     t2 = RPMTAG_POSTUNPROG;
  1028.     break;
  1029.       case VERIFYSCRIPT_PART:
  1030.     t1 = RPMTAG_VERIFYSCRIPT;
  1031.     break;
  1032.       case DESCRIPTION_PART:
  1033.     t1 = RPMTAG_DESCRIPTION;
  1034.     break;
  1035.       case CHANGELOG_PART:
  1036.     /* %changelog is a little special.  It goes in the   */
  1037.     /* "main" package no matter where it appears, and it */
  1038.     /* ends up in all the packages.                      */
  1039.     if (addChangelog(spec->packages->header, sb)) {
  1040.         return 1;
  1041.     }
  1042.     break;
  1043.       case TRIGGERIN_PART:
  1044.     if (addTrigger(cur_package, RPMSENSE_TRIGGER_IN,
  1045.                getStringBuf(sb), triggerArgs)) {
  1046.         return 1;
  1047.     }
  1048.     break;
  1049.       case TRIGGERUN_PART:
  1050.     if (addTrigger(cur_package, RPMSENSE_TRIGGER_UN,
  1051.                getStringBuf(sb), triggerArgs)) {
  1052.         return 1;
  1053.     }
  1054.     break;
  1055.     }
  1056.     if (t1 && (*(getStringBuf(sb)) != '\0')) {
  1057.     headerAddEntry(cur_package->header, t1,
  1058.                RPM_STRING_TYPE, getStringBuf(sb), 1);
  1059.     }
  1060.     if (t2) {
  1061.     addReqProv(cur_package, RPMSENSE_PREREQ, scriptProg, NULL);
  1062.     headerAddEntry(cur_package->header, t2,
  1063.                RPM_STRING_TYPE, scriptProg, 1);
  1064.     }
  1065.     return 0;
  1066. }
  1067.  
  1068. /**********************************************************************/
  1069. /*                                                                    */
  1070. /* Main specfile parsing routine                                      */
  1071. /*                                                                    */
  1072. /**********************************************************************/
  1073.  
  1074. Spec *parseSpec(FILE *f, char *specfile, char *buildRootOverride)
  1075. {
  1076.     Spec *res;
  1077.     Spec s;
  1078.     char **archs = NULL;
  1079.     char **arch;
  1080.     int i, count;
  1081.     
  1082.     s = parseSpecAux(f, specfile, buildRootOverride, &archs);
  1083.  
  1084.     if (s) {
  1085.     /* No BuildArchitectures field */
  1086.     res = (Spec *) malloc(2 * sizeof(Spec));
  1087.     res[0] = s;
  1088.     res[1] = NULL;
  1089.     return res;
  1090.     }
  1091.  
  1092.     if (! archs) {
  1093.     /* Error */
  1094.     return NULL;
  1095.     }
  1096.  
  1097.     /* We have a BuildArchitectures field */
  1098.     count = 0;
  1099.     while (archs[count]) {
  1100.     count++;
  1101.     }
  1102.     res = (Spec *) malloc(count * sizeof(Spec));
  1103.  
  1104.     i = 0;
  1105.     arch = archs;
  1106.     while (*arch) {
  1107.     if (rpmMachineScore(RPM_MACHTABLE_BUILDARCH, *arch)) {
  1108.         rewind(f);
  1109.         rpmSetMachine(*arch, NULL);
  1110.         res[i] = parseSpecAux(f, specfile, buildRootOverride, NULL);
  1111.         if (! res[i]) {
  1112.         /* Error */
  1113.         freeSplitString(archs);
  1114.         while (i) {
  1115.             i--;
  1116.             freeSpec(res[i]);
  1117.         }
  1118.         free(res);
  1119.         return NULL;
  1120.         }
  1121.         headerAddEntry(res[i]->packages->header, RPMTAG_BUILDARCHS,
  1122.                RPM_STRING_ARRAY_TYPE, archs, count);
  1123.         res[i]->buildArch = strdup(*arch);
  1124.         i++;
  1125.     }
  1126.     arch++;
  1127.     }
  1128.     res[i] = NULL;
  1129.  
  1130.     freeSplitString(archs);
  1131.     
  1132.     return res;
  1133. }
  1134.  
  1135. Spec parseSpecAux(FILE *f, char *specfile, char *buildRootOverride,
  1136.           char ***buildArchs)
  1137. {
  1138.     char buf[LINE_BUF_SIZE]; /* read buffer          */
  1139.     char buf2[LINE_BUF_SIZE];
  1140.     char fileFile[LINE_BUF_SIZE];
  1141.     char scriptProg[LINE_BUF_SIZE];
  1142.     char triggerArgs[LINE_BUF_SIZE];
  1143.     char *line;              /* "parsed" read buffer */
  1144.     
  1145.     int x, serial, tag, cur_part;
  1146.     int lookupopts;
  1147.     StringBuf sb;
  1148.     char *s = NULL;
  1149.     char *s1, *s2;
  1150.     int gotBuildroot = 0;
  1151.     int gotRoot = 0;
  1152.     int versionMacroSet = 0;
  1153.     int releaseMacroSet = 0;
  1154.  
  1155.     struct PackageRec *cur_package = NULL;
  1156.     Spec spec = (struct SpecRec *) malloc(sizeof(struct SpecRec));
  1157.  
  1158.     spec->name = NULL;
  1159.     spec->specfile = strdup(specfile);
  1160.     spec->numSources = 0;
  1161.     spec->numPatches = 0;
  1162.     spec->sources = NULL;
  1163.     spec->prep = newStringBuf();
  1164.     spec->build = newStringBuf();
  1165.     spec->install = newStringBuf();
  1166.     spec->doc = newStringBuf();
  1167.     spec->clean = newStringBuf();
  1168.     spec->packages = NULL;
  1169.     spec->noSource = NULL;
  1170.     spec->noPatch = NULL;
  1171.     spec->numNoSource = 0;
  1172.     spec->numNoPatch = 0;
  1173.     spec->buildroot = NULL;
  1174.     spec->autoReqProv = 1;
  1175.     spec->buildArch = NULL;
  1176.  
  1177.     sb = newStringBuf();
  1178.     reset_spec();         /* Reset the parser */
  1179.  
  1180.     scriptProg[0] = '\0';
  1181.     cur_part = PREAMBLE_PART;
  1182.     while ((x = read_line(f, buf)) > 0) {
  1183.     line = buf;
  1184.     s = NULL;
  1185.         if ((tag = check_part(line, &s))) {
  1186.         rpmMessage(RPMMESS_DEBUG, "Switching to part: %d\n", tag);
  1187.         if (finishCurrentPart(spec, sb, cur_package,
  1188.                  cur_part, triggerArgs, scriptProg)) {
  1189.         return NULL;
  1190.         }
  1191.         cur_part = tag;
  1192.         truncStringBuf(sb);
  1193.  
  1194.         /* Now switch the current package to s */
  1195.         if (s) {
  1196.             switch (tag) {
  1197.           case PREP_PART:
  1198.           case BUILD_PART:
  1199.           case INSTALL_PART:
  1200.           case CLEAN_PART:
  1201.           case CHANGELOG_PART:
  1202.             rpmError(RPMERR_BADARG, "Tag takes no arguments: %s", s);
  1203.             return NULL;
  1204.             }
  1205.         }
  1206.  
  1207.         /* Rip through s for -f in %files */
  1208.         /* not only is this code disgusting, but it allows -f on any tag */
  1209.         fileFile[0] = '\0';
  1210.         s1 = NULL;
  1211.         if (s &&
  1212.         ((s1 = strstr(s, " -f ")) ||
  1213.          (!strncmp(s, "-f ", 3)))) {
  1214.         if (s1) {
  1215.             s1[0] = ' ';
  1216.             s1++;
  1217.         } else {
  1218.             s1 = s;
  1219.         }
  1220.         s1[0] = ' '; s1[1] = ' '; s1[2] = ' ';
  1221.         s1 += 3;
  1222.         while (isspace(*s1)) {
  1223.             s1++;
  1224.         }
  1225.  
  1226.         s2 = fileFile;
  1227.         while (*s1 && !isspace(*s1)) {
  1228.             *s2 = *s1;
  1229.             *s1 = ' ';
  1230.             s1++;
  1231.             s2++;
  1232.         }
  1233.         *s2 = '\0';
  1234.         while (isspace(*s)) {
  1235.             s++;
  1236.         }
  1237.         if (! *s) {
  1238.             s = NULL;
  1239.         }
  1240.         }
  1241.  
  1242.         rpmMessage(RPMMESS_DEBUG, "fileFile = %s\n", 
  1243.             fileFile[0] ? fileFile : "(null)");
  1244.  
  1245.         /* If trigger, pull off the args */
  1246.         if (tag == TRIGGERIN_PART || tag == TRIGGERUN_PART) {
  1247.         s1 = strstr(s, "--");
  1248.         if (s1) {
  1249.             strcpy(triggerArgs, s1+2);
  1250.             *s1 = '\0';
  1251.             s = strtok(s, " \n\t");
  1252.         } else {
  1253.             strcpy(triggerArgs, s);
  1254.             s = NULL;
  1255.         }
  1256.         }
  1257.  
  1258.         /* find possible -p <prog> */
  1259.         if ((tag == PREIN_PART) ||
  1260.         (tag == POSTIN_PART) ||
  1261.         (tag == PREUN_PART) ||
  1262.         (tag == POSTUN_PART)) {
  1263.  
  1264.         scriptProg[0] = '\0';
  1265.         s1 = NULL;
  1266.  
  1267.         if (s &&
  1268.             ((s1 = strstr(s, " -p ")) ||
  1269.              (!strncmp(s, "-p ", 3)))) {
  1270.             
  1271.             if (s1) {
  1272.             s1[0] = ' ';
  1273.             s1++;
  1274.             } else {
  1275.             s1 = s;
  1276.             }
  1277.             s1[0] = ' '; s1[1] = ' '; s1[2] = ' ';
  1278.             s1 += 3;
  1279.             while (isspace(*s1)) {
  1280.             s1++;
  1281.             }
  1282.             
  1283.             s2 = scriptProg;
  1284.             while (*s1 && !isspace(*s1)) {
  1285.             *s2 = *s1;
  1286.             *s1 = ' ';
  1287.             s1++;
  1288.             s2++;
  1289.             }
  1290.  
  1291.             *s2 = '\0';
  1292.             while (isspace(*s)) {
  1293.             s++;
  1294.             }
  1295.             if (! *s) {
  1296.             s = NULL;
  1297.             }
  1298.         }
  1299.         
  1300.         /* defaults to /bin/sh */
  1301.         if (! scriptProg[0]) {
  1302.             strcpy(scriptProg, "/bin/sh");
  1303.         } else {
  1304.             if (scriptProg[0] != '/') {
  1305.             rpmError(RPMERR_BADSPEC, "pre/post -p arg must begin with \'/\': %s", scriptProg);
  1306.             return NULL;
  1307.             }
  1308.         }
  1309.         rpmMessage(RPMMESS_DEBUG, "scriptProg = %s\n", scriptProg);
  1310.         }
  1311.         
  1312.         /* At this point s is the remaining args, which can only */
  1313.         /* be -n <pkg>, or simply <pkg>.                         */
  1314.         
  1315.         /* Handle -n in part tags */
  1316.         lookupopts = 0;
  1317.         if (s) {
  1318.         if (!strncmp(s, "-n", 2)) {
  1319.             s += 2;
  1320.             s += strspn(s, ": \t");
  1321.             if (*s == '\0') {
  1322.             rpmError(RPMERR_BADARG, "-n takes argument");
  1323.             return NULL;
  1324.             }
  1325.             lookupopts = LP_NEWNAME;
  1326.         } else {
  1327.             lookupopts = LP_SUBNAME;
  1328.         }
  1329.             /* Handle trailing whitespace */
  1330.             s1 = s + strlen(s) - 1;
  1331.             while (*s1 == ' ' || *s1 == '\n' || *s1 == '\t') {
  1332.            s1--;
  1333.         }
  1334.             s1++;
  1335.             *s1 = '\0';
  1336.         }
  1337.         
  1338.         switch (tag) {
  1339.           case PREP_PART:
  1340.           case BUILD_PART:
  1341.           case INSTALL_PART:
  1342.           case CLEAN_PART:
  1343.           case CHANGELOG_PART:
  1344.             /* Do not switch parts for these */
  1345.             break;
  1346.           case PREAMBLE_PART:
  1347.             lookupopts |= LP_CREATE | LP_FAIL_EXISTS;
  1348.             /* Fall through */
  1349.           default:
  1350.             /* XXX - should be able to drop the -n in non-%package parts */
  1351.             if (! lookup_package(spec, &cur_package, s, lookupopts)) {
  1352.             rpmError(RPMERR_INTERNAL, "Package lookup failed: %s",
  1353.                  (s) ? s : "(main)");
  1354.             return NULL;
  1355.             }
  1356.             rpmMessage(RPMMESS_DEBUG, "Switched to package: %s\n", 
  1357.             s ? s : "(main)");
  1358.         }
  1359.  
  1360.         if (cur_part == FILES_PART) {
  1361.         /* set files to 0 (current -1 means no %files, no package */
  1362.         cur_package->files = 0;
  1363.         if (fileFile[0]) {
  1364.             cur_package->fileFile = strdup(fileFile);
  1365.         }
  1366.         }
  1367.  
  1368.         /* This line has no content -- it was just a control line */
  1369.         continue;
  1370.         }
  1371.  
  1372.     /* Check for implicit "base" package.                        */
  1373.         /* That means that the specfile does not start with %package */
  1374.     if (! cur_package) {
  1375.         lookupopts = 0;
  1376.         if (cur_part == PREAMBLE_PART) {
  1377.         lookupopts = LP_CREATE | LP_FAIL_EXISTS;
  1378.         }
  1379.         if (! lookup_package(spec, &cur_package, NULL, lookupopts)) {
  1380.         rpmError(RPMERR_INTERNAL, "Base package lookup failed!");
  1381.         return NULL;
  1382.         }
  1383.         rpmMessage(RPMMESS_DEBUG, "Switched to BASE package\n");
  1384.     }
  1385.  
  1386.     switch (cur_part) {
  1387.       case PREAMBLE_PART:
  1388.         if ((tag = find_preamble_line(line, &s))) {
  1389.             switch (tag) {
  1390.           case RPMTAG_EXCLUDE:
  1391.           case RPMTAG_EXCLUSIVE:
  1392.               rpmMessage(RPMMESS_WARNING,
  1393.                   "Exclude/Exclusive are depricated.\n"
  1394.                   "Use ExcludeArch/ExclusiveArch instead.\n");
  1395.               sprintf(buf2, "%s %s",
  1396.                   (tag == RPMTAG_EXCLUDE) ? "%ifarch" : "%ifnarch",
  1397.                   s);
  1398.               if (match_arch(buf2)) {
  1399.               rpmError(RPMERR_BADARCH, "Arch mismatch!");
  1400.               return NULL;
  1401.               }
  1402.               addListEntry(cur_package->header,
  1403.                    (tag == RPMTAG_EXCLUDE) ?
  1404.                    RPMTAG_EXCLUDEARCH : RPMTAG_EXCLUSIVEARCH,
  1405.                    s);
  1406.               break;
  1407.           case RPMTAG_EXCLUDEARCH:    
  1408.           case RPMTAG_EXCLUSIVEARCH:
  1409.             sprintf(buf2, "%s %s", (tag == RPMTAG_EXCLUDEARCH) ?
  1410.                 "%ifarch" : "%ifnarch",  s);
  1411.             if (match_arch(buf2)) {
  1412.             rpmError(RPMERR_BADARCH, "Arch mismatch!");
  1413.             return NULL;
  1414.             }
  1415.             addListEntry(cur_package->header, tag, s);
  1416.             break;
  1417.           case RPMTAG_EXCLUDEOS:
  1418.           case RPMTAG_EXCLUSIVEOS:
  1419.             sprintf(buf2, "%s %s", (tag == RPMTAG_EXCLUDEOS) ?
  1420.                 "%ifos" : "%ifnos",  s);
  1421.             if (match_os(buf2)) {
  1422.             rpmError(RPMERR_BADOS, "OS mismatch!");
  1423.             return NULL;
  1424.             }
  1425.             addListEntry(cur_package->header, tag, s);
  1426.             break;
  1427.           case RPMTAG_NAME:
  1428.             s1 = s;
  1429.             while (*s1 && *s1 != ' ' && *s1 != '\t') s1++;
  1430.             *s1 = '\0';
  1431.             if (!spec->name) {
  1432.             spec->name = strdup(s);
  1433.             }
  1434.             /* The NAME entries must be generated after */
  1435.             /* the whole spec file is parsed.           */
  1436.             break;
  1437.           case RPMTAG_VERSION:
  1438.           case RPMTAG_RELEASE:
  1439.             s1 = s;
  1440.             while (*s1 && *s1 != ' ' && *s1 != '\t') s1++;
  1441.             *s1 = '\0';
  1442.             if (s1 == s) {
  1443.             rpmError(RPMERR_BADSPEC, (tag == RPMTAG_VERSION) ?
  1444.                  "Empty version field." :
  1445.                  "Empty release field.");
  1446.             return NULL;
  1447.             }
  1448.             if (tag == RPMTAG_VERSION) {
  1449.             if (! versionMacroSet) {
  1450.                 versionMacroSet = 1;
  1451.                 addMacro("PACKAGE_VERSION", s);
  1452.             }
  1453.             } else {
  1454.             if (! releaseMacroSet) {
  1455.                 releaseMacroSet = 1;
  1456.                 addMacro("PACKAGE_RELEASE", s);
  1457.             }
  1458.             }
  1459.           case RPMTAG_SUMMARY:
  1460.           case RPMTAG_DISTRIBUTION:
  1461.           case RPMTAG_VENDOR:
  1462.           case RPMTAG_COPYRIGHT:
  1463.           case RPMTAG_PACKAGER:
  1464.           case RPMTAG_GROUP:
  1465.           case RPMTAG_URL:
  1466.             headerAddEntry(cur_package->header, tag, RPM_STRING_TYPE, s, 1);
  1467.             break;
  1468.           case RPMTAG_BUILDARCHS:
  1469.             if (buildArchs) {
  1470.             *buildArchs = splitString(s, strlen(s), ' ');
  1471.             freeSpec(spec);
  1472.             freeStringBuf(sb);
  1473.             return NULL;
  1474.             }
  1475.             break;
  1476.           case RPMTAG_BUILDROOT:
  1477.             gotBuildroot = 1;
  1478.             spec->buildroot = strdup(s);
  1479.             break;
  1480.           case RPMTAG_DEFAULTPREFIX:
  1481.             headerAddEntry(cur_package->header, tag, RPM_STRING_TYPE, s, 1);
  1482.             break;
  1483.           case RPMTAG_SERIAL:
  1484.             serial = atoi(s);
  1485.             headerAddEntry(cur_package->header, tag, RPM_INT32_TYPE, &serial, 1);
  1486.             break;
  1487.           case RPMTAG_DESCRIPTION:
  1488.             /* Special case -- need to handle backslash */
  1489.             truncStringBuf(sb);
  1490.             while (1) {
  1491.                 s1 = s + strlen(s) - 1;
  1492.             if (*s1 != '\\') {
  1493.                 break;
  1494.             }
  1495.                 *s1 = '\0';
  1496.             appendLineStringBuf(sb, s);
  1497.             read_line(f, buf);
  1498.             s = buf;
  1499.             }
  1500.             appendStringBuf(sb, s);
  1501.             headerAddEntry(cur_package->header, RPMTAG_DESCRIPTION,
  1502.                  RPM_STRING_TYPE, getStringBuf(sb), 1);
  1503.             break;
  1504.           case RPMTAG_ROOT:
  1505.             /* special case */
  1506.             gotRoot = 1;
  1507.             rpmMessage(RPMMESS_DEBUG, "Got root: %s\n", s);
  1508.             rpmMessage(RPMMESS_WARNING, "The Root: tag is depricated.  Use Buildroot: instead\n");
  1509.             rpmSetVar(RPMVAR_ROOT, s);
  1510.             break;
  1511.           case RPMTAG_ICON:
  1512.               cur_package->icon = strdup(s);
  1513.               break;
  1514.           case RPMTAG_NOPATCH:
  1515.           case RPMTAG_NOSOURCE:
  1516.               if (noSourcePatch(spec, s, tag)) {
  1517.               return NULL;
  1518.               }
  1519.               break;
  1520.           case RPMTAG_SOURCE:
  1521.           case RPMTAG_PATCH:
  1522.               if (addSource(spec, line)) {
  1523.               return NULL;
  1524.               }
  1525.               break;
  1526.           case RPMTAG_OBSOLETES:
  1527.           case RPMTAG_PROVIDES:
  1528.               if (parseProvides(cur_package, s, tag)) {
  1529.               return NULL;
  1530.               }
  1531.               break;
  1532.           case RPMTAG_REQUIREFLAGS:
  1533.           case RPMTAG_CONFLICTFLAGS:
  1534.           case RPMTAG_PREREQ:
  1535.               if (parseRequiresConflicts(cur_package, s, tag)) {
  1536.               return NULL;
  1537.               }
  1538.               break;
  1539.           case RPMTAG_AUTOREQPROV:
  1540.             s1 = strtok(s, " \t\n");
  1541.             if (!s1) {
  1542.             spec->autoReqProv = 0;
  1543.             } else if (s1[0] == 'n' || s1[0] == 'N') {
  1544.             spec->autoReqProv = 0;
  1545.             } else if (!strcasecmp(s1, "false")) {
  1546.             spec->autoReqProv = 0;
  1547.             } else if (!strcasecmp(s1, "off")) {
  1548.             spec->autoReqProv = 0;
  1549.             } else if (!strcmp(s1, "0")) {
  1550.             spec->autoReqProv = 0;
  1551.             }
  1552.             break;
  1553.           default:
  1554.               /* rpmMessage(RPMMESS_DEBUG, "Skipping: %s\n", line); */
  1555.               /* This shouldn't happen? */
  1556.               rpmError(RPMERR_INTERNAL, "Bogus token");
  1557.               return NULL;
  1558.         }        
  1559.         } else {
  1560.             /* Not a recognized preamble part */
  1561.         s1 = line;
  1562.         while (*s1 && (*s1 == ' ' || *s1 == '\t')) s1++;
  1563.         /* Handle blanks lines and comments */
  1564.         if (*s1 && (*s1 != '#')) {
  1565.             /*rpmMessage(RPMMESS_WARNING, "Unknown Field: %s\n", line);*/
  1566.             rpmError(RPMERR_BADSPEC, "Unknown Field: %s\n", line);
  1567.             return NULL;
  1568.         }
  1569.         }
  1570.         break;
  1571.       case PREP_PART:
  1572.         appendLineStringBuf(spec->prep, line);
  1573.         break;
  1574.       case BUILD_PART:
  1575.         appendLineStringBuf(spec->build, line);
  1576.         break;
  1577.       case INSTALL_PART:
  1578.         appendLineStringBuf(spec->install, line);
  1579.         break;
  1580.       case CLEAN_PART:
  1581.         appendLineStringBuf(spec->clean, line);
  1582.         break;
  1583.       case DESCRIPTION_PART:
  1584.       case CHANGELOG_PART:
  1585.       case PREIN_PART:
  1586.       case POSTIN_PART:
  1587.       case PREUN_PART:
  1588.       case POSTUN_PART:
  1589.       case VERIFYSCRIPT_PART:
  1590.         appendLineStringBuf(sb, line);
  1591.         break;
  1592.       case TRIGGERIN_PART:
  1593.       case TRIGGERUN_PART:
  1594.         appendLineStringBuf(sb, line);
  1595.         break;
  1596.       case FILES_PART:
  1597.           s1 = line;
  1598.           while (*s1 && (*s1 == ' ' || *s1 == '\t')) s1++;
  1599.           /* Handle blanks lines and comments */
  1600.           if (*s1 && (*s1 != '#')) {
  1601.           cur_package->files++;
  1602.           appendLineStringBuf(cur_package->filelist, line);
  1603.           }
  1604.         break;
  1605.       default:
  1606.         rpmError(RPMERR_INTERNAL, "Bad part");
  1607.         return NULL;
  1608.     } /* switch */
  1609.     }
  1610.     if (x < 0) {
  1611.     return NULL;
  1612.     }
  1613.  
  1614.     /* finish current part */
  1615.     if (finishCurrentPart(spec, sb, cur_package,
  1616.               cur_part, triggerArgs,
  1617.               scriptProg)) {
  1618.     return NULL;
  1619.     }
  1620.  
  1621.     freeStringBuf(sb);
  1622.     
  1623.     if (gotRoot && gotBuildroot) {
  1624.     freeSpec(spec);
  1625.     rpmError(RPMERR_BADSPEC,
  1626.           "Spec file can not have both Root: and Buildroot:");
  1627.     return NULL;
  1628.     }
  1629.     if (spec->buildroot) {
  1630.     /* This package can do build roots */
  1631.     if (buildRootOverride) {
  1632.         rpmSetVar(RPMVAR_ROOT, buildRootOverride);
  1633.         rpmSetVar(RPMVAR_BUILDROOT, buildRootOverride);
  1634.     } else {
  1635.         if ((s = rpmGetVar(RPMVAR_BUILDROOT))) {
  1636.         /* Take build prefix from rpmrc */
  1637.         rpmSetVar(RPMVAR_ROOT, s);
  1638.         } else {
  1639.         /* Use default */
  1640.         rpmSetVar(RPMVAR_ROOT, spec->buildroot);
  1641.         rpmSetVar(RPMVAR_BUILDROOT, spec->buildroot);
  1642.         }
  1643.     }
  1644.     } else {
  1645.     /* Package can not do build prefixes */
  1646.     if (buildRootOverride) {
  1647.         freeSpec(spec);
  1648.         rpmError(RPMERR_BADARG, "Package can not do build prefixes");
  1649.         return NULL;
  1650.     }
  1651.     }
  1652.  
  1653.     generateNames(spec);
  1654.     return spec;
  1655. }
  1656.  
  1657. /**********************************************************************/
  1658. /*                                                                    */
  1659. /* Resets the parser                                                  */
  1660. /*                                                                    */
  1661. /**********************************************************************/
  1662.  
  1663. static void reset_spec()
  1664. {
  1665.     static done = 0;
  1666.     struct read_level_entry *rl;
  1667.     struct preamble_line *p = preamble_spec;
  1668.     struct part_rec *p1 = part_list;
  1669.  
  1670.     rpmSetVar(RPMVAR_ROOT, NULL);
  1671.  
  1672.     while (read_level) {
  1673.     rl = read_level;
  1674.         read_level = read_level->next;
  1675.     free(rl);
  1676.     }
  1677.     read_level = malloc(sizeof(struct read_level_entry));
  1678.     read_level->next = NULL;
  1679.     read_level->reading = 1;
  1680.  
  1681.     resetMacros();
  1682.     
  1683.     if (! done) {
  1684.         /* Put one time only things in here */
  1685.         while (p->tag) {
  1686.         p->len = strlen(p->token);
  1687.         p++;
  1688.     }
  1689.         while (p1->part) {
  1690.         p1->len = strlen(p1->s);
  1691.         p1++;
  1692.     }
  1693.  
  1694.     done = 1;
  1695.     }
  1696. }
  1697.  
  1698. /**********************************************************************/
  1699. /*                                                                    */
  1700. /* Spec struct dumping (for debugging)                                */
  1701. /*                                                                    */
  1702. /**********************************************************************/
  1703.  
  1704. void dumpSpec(Spec s, FILE *f)
  1705. {
  1706.     struct PackageRec *p;
  1707.     
  1708.     fprintf(f, "########################################################\n");
  1709.     fprintf(f, "SPEC NAME = (%s)\n", s->name);
  1710.     fprintf(f, "PREP =v\n");
  1711.     fprintf(f, "%s", getStringBuf(s->prep));
  1712.     fprintf(f, "PREP =^\n");
  1713.     fprintf(f, "BUILD =v\n");
  1714.     fprintf(f, "%s", getStringBuf(s->build));
  1715.     fprintf(f, "BUILD =^\n");
  1716.     fprintf(f, "INSTALL =v\n");
  1717.     fprintf(f, "%s", getStringBuf(s->install));
  1718.     fprintf(f, "INSTALL =^\n");
  1719.     fprintf(f, "CLEAN =v\n");
  1720.     fprintf(f, "%s", getStringBuf(s->clean));
  1721.     fprintf(f, "CLEAN =^\n");
  1722.  
  1723.     p = s->packages;
  1724.     while (p) {
  1725.     dumpPackage(p, f);
  1726.     p = p->next;
  1727.     }
  1728. }
  1729.  
  1730. static void dumpPackage(struct PackageRec *p, FILE *f)
  1731. {
  1732.     fprintf(f, "_________________________________________________________\n");
  1733.     fprintf(f, "SUBNAME = (%s)\n", p->subname);
  1734.     fprintf(f, "NEWNAME = (%s)\n", p->newname);
  1735.     fprintf(f, "FILES = %d\n", p->files);
  1736.     fprintf(f, "FILES =v\n");
  1737.     fprintf(f, "%s", getStringBuf(p->filelist));
  1738.     fprintf(f, "FILES =^\n");
  1739.     fprintf(f, "HEADER =v\n");
  1740.     headerDump(p->header, f, 1, rpmTagTable);
  1741.     fprintf(f, "HEADER =^\n");
  1742.  
  1743. }
  1744.