00001
00006 #include "system.h"
00007
00008 static int _debug = 0;
00009
00010 #include <rpmio_internal.h>
00011 #include <rpmbuild.h>
00012 #include "debug.h"
00013
00016 static struct PartRec {
00017 int part;
00018 int len;
00019 char *token;
00020 } partList[] = {
00021 { PART_PREAMBLE, 0, "%package"},
00022 { PART_PREP, 0, "%prep"},
00023 { PART_BUILD, 0, "%build"},
00024 { PART_INSTALL, 0, "%install"},
00025 { PART_CLEAN, 0, "%clean"},
00026 { PART_PREUN, 0, "%preun"},
00027 { PART_POSTUN, 0, "%postun"},
00028 { PART_PRE, 0, "%pre"},
00029 { PART_POST, 0, "%post"},
00030 { PART_FILES, 0, "%files"},
00031 { PART_CHANGELOG, 0, "%changelog"},
00032 { PART_DESCRIPTION, 0, "%description"},
00033 { PART_TRIGGERPOSTUN, 0, "%triggerpostun"},
00034 { PART_TRIGGERUN, 0, "%triggerun"},
00035 { PART_TRIGGERIN, 0, "%triggerin"},
00036 { PART_TRIGGERIN, 0, "%trigger"},
00037 { PART_VERIFYSCRIPT, 0, "%verifyscript"},
00038 {0, 0, 0}
00039 };
00040
00043 static inline void initParts(struct PartRec *p)
00044 {
00045 for (; p->token != NULL; p++)
00046 p->len = strlen(p->token);
00047 }
00048
00049 rpmParseState isPart(const char *line)
00050 {
00051 struct PartRec *p;
00052
00053 if (partList[0].len == 0)
00054 initParts(partList);
00055
00056 for (p = partList; p->token != NULL; p++) {
00057 char c;
00058 if (xstrncasecmp(line, p->token, p->len))
00059 continue;
00060 c = *(line + p->len);
00061 if (c == '\0' || isspace(c))
00062 break;
00063 }
00064
00065 return (p->token ? p->part : PART_NONE);
00066 }
00067
00070 static int matchTok(const char *token, const char *line)
00071 {
00072 const char *b, *be = line;
00073 size_t toklen = strlen(token);
00074 int rc = 0;
00075
00076 while ( *(b = be) ) {
00077 SKIPSPACE(b);
00078 be = b;
00079 SKIPNONSPACE(be);
00080 if (be == b)
00081 break;
00082 if (toklen != (be-b) || xstrncasecmp(token, b, (be-b)))
00083 continue;
00084 rc = 1;
00085 break;
00086 }
00087
00088 return rc;
00089 }
00090
00091 void handleComments(char *s)
00092 {
00093 SKIPSPACE(s);
00094 if (*s == '#')
00095 *s = '\0';
00096 }
00097
00100 static void forceIncludeFile(Spec spec, const char * fileName)
00101 {
00102 OFI_t * ofi;
00103
00104 ofi = newOpenFileInfo();
00105 ofi->fileName = xstrdup(fileName);
00106 ofi->next = spec->fileStack;
00107 spec->fileStack = ofi;
00108 }
00109
00112 static int copyNextLine(Spec spec, OFI_t *ofi, int strip)
00113 {
00114 char *last;
00115 char ch;
00116
00117
00118 if (spec->nextline != NULL && spec->nextpeekc != '\0') {
00119 *spec->nextline = spec->nextpeekc;
00120 spec->nextpeekc = '\0';
00121 }
00122
00123 if (!(spec->nextline && *spec->nextline)) {
00124 char *from, *to;
00125 to = last = spec->lbuf;
00126 from = ofi->readPtr;
00127 ch = ' ';
00128 while (*from && ch != '\n')
00129 ch = *to++ = *from++;
00130 *to++ = '\0';
00131 ofi->readPtr = from;
00132
00133
00134 if (spec->readStack->reading &&
00135 expandMacros(spec, spec->macros, spec->lbuf, sizeof(spec->lbuf))) {
00136 rpmError(RPMERR_BADSPEC, _("line %d: %s\n"),
00137 spec->lineNum, spec->lbuf);
00138 return RPMERR_BADSPEC;
00139 }
00140 spec->nextline = spec->lbuf;
00141 }
00142
00143
00144 spec->line = last = spec->nextline;
00145 ch = ' ';
00146 while (*spec->nextline && ch != '\n') {
00147 ch = *spec->nextline++;
00148 if (!isspace(ch))
00149 last = spec->nextline;
00150 }
00151
00152
00153 if (*spec->nextline) {
00154 spec->nextpeekc = *spec->nextline;
00155 *spec->nextline = '\0';
00156 }
00157
00158 if (strip & STRIP_COMMENTS)
00159 handleComments(spec->line);
00160
00161 if (strip & STRIP_TRAILINGSPACE)
00162 *last = '\0';
00163
00164 return 0;
00165 }
00166
00167 int readLine(Spec spec, int strip)
00168 {
00169 #ifdef DYING
00170 const char *arch;
00171 const char *os;
00172 #endif
00173 char *s;
00174 int match;
00175 struct ReadLevelEntry *rl;
00176 OFI_t *ofi = spec->fileStack;
00177 int rc;
00178
00179 retry:
00180
00181 if (ofi->fd == NULL) {
00182 ofi->fd = Fopen(ofi->fileName, "r.fpio");
00183 if (ofi->fd == NULL || Ferror(ofi->fd)) {
00184
00185 rpmError(RPMERR_BADSPEC, _("Unable to open %s: %s\n"),
00186 ofi->fileName, Fstrerror(ofi->fd));
00187 return RPMERR_BADSPEC;
00188 }
00189 spec->lineNum = ofi->lineNum = 0;
00190 }
00191
00192
00193 if (!(ofi->readPtr && *(ofi->readPtr))) {
00194 if (!fgets(ofi->readBuf, BUFSIZ, fdGetFp(ofi->fd))) {
00195
00196 if (spec->readStack->next) {
00197 rpmError(RPMERR_UNMATCHEDIF, _("Unclosed %%if\n"));
00198 return RPMERR_UNMATCHEDIF;
00199 }
00200
00201
00202 spec->fileStack = ofi->next;
00203 Fclose(ofi->fd);
00204 FREE(ofi->fileName);
00205 free(ofi);
00206
00207
00208 ofi = spec->fileStack;
00209 if (ofi == NULL)
00210 return 1;
00211
00212
00213 goto retry;
00214 }
00215 ofi->readPtr = ofi->readBuf;
00216 ofi->lineNum++;
00217 spec->lineNum = ofi->lineNum;
00218 if (spec->sl) {
00219 struct speclines *sl = spec->sl;
00220 if (sl->sl_nlines == sl->sl_nalloc) {
00221 sl->sl_nalloc += 100;
00222 sl->sl_lines = (char **) xrealloc(sl->sl_lines,
00223 sl->sl_nalloc * sizeof(*(sl->sl_lines)));
00224 }
00225 sl->sl_lines[sl->sl_nlines++] = xstrdup(ofi->readBuf);
00226 }
00227 }
00228
00229 #ifdef DYING
00230 arch = NULL;
00231 rpmGetArchInfo(&arch, NULL);
00232 os = NULL;
00233 rpmGetOsInfo(&os, NULL);
00234 #endif
00235
00236
00237 if ((rc = copyNextLine(spec, ofi, strip)) != 0)
00238 return rc;
00239
00240 s = spec->line;
00241 SKIPSPACE(s);
00242
00243 match = -1;
00244 if (! strncmp("%ifarch", s, sizeof("%ifarch")-1)) {
00245 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00246 s += 7;
00247 match = matchTok(arch, s);
00248 free((void *)arch);
00249 } else if (! strncmp("%ifnarch", s, sizeof("%ifnarch")-1)) {
00250 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00251 s += 8;
00252 match = !matchTok(arch, s);
00253 free((void *)arch);
00254 } else if (! strncmp("%ifos", s, sizeof("%ifos")-1)) {
00255 const char *os = rpmExpand("%{_target_os}", NULL);
00256 s += 5;
00257 match = matchTok(os, s);
00258 free((void *)os);
00259 } else if (! strncmp("%ifnos", s, sizeof("%ifnos")-1)) {
00260 const char *os = rpmExpand("%{_target_os}", NULL);
00261 s += 6;
00262 match = !matchTok(os, s);
00263 free((void *)os);
00264 } else if (! strncmp("%if", s, sizeof("%if")-1)) {
00265 s += 3;
00266 match = parseExpressionBoolean(spec, s);
00267 if (match < 0) {
00268 rpmError(RPMERR_UNMATCHEDIF,
00269 _("%s:%d: parseExpressionBoolean returns %d\n"),
00270 ofi->fileName, ofi->lineNum, match);
00271 return RPMERR_BADSPEC;
00272 }
00273 } else if (! strncmp("%else", s, sizeof("%else")-1)) {
00274 s += 5;
00275 if (! spec->readStack->next) {
00276
00277 rpmError(RPMERR_UNMATCHEDIF,
00278 _("%s:%d: Got a %%else with no %%if\n"),
00279 ofi->fileName, ofi->lineNum);
00280 return RPMERR_UNMATCHEDIF;
00281 }
00282 spec->readStack->reading =
00283 spec->readStack->next->reading && ! spec->readStack->reading;
00284 spec->line[0] = '\0';
00285 } else if (! strncmp("%endif", s, sizeof("%endif")-1)) {
00286 s += 6;
00287 if (! spec->readStack->next) {
00288
00289 rpmError(RPMERR_UNMATCHEDIF,
00290 _("%s:%d: Got a %%endif with no %%if\n"),
00291 ofi->fileName, ofi->lineNum);
00292 return RPMERR_UNMATCHEDIF;
00293 }
00294 rl = spec->readStack;
00295 spec->readStack = spec->readStack->next;
00296 free(rl);
00297 spec->line[0] = '\0';
00298 } else if (! strncmp("%include", s, sizeof("%include")-1)) {
00299 char *fileName, *endFileName, *p;
00300
00301 s += 8;
00302 fileName = s;
00303 if (! isspace(*fileName)) {
00304 rpmError(RPMERR_BADSPEC, _("malformed %%include statement\n"));
00305 return RPMERR_BADSPEC;
00306 }
00307 SKIPSPACE(fileName);
00308 endFileName = fileName;
00309 SKIPNONSPACE(endFileName);
00310 p = endFileName;
00311 SKIPSPACE(p);
00312 if (*p != '\0') {
00313 rpmError(RPMERR_BADSPEC, _("malformed %%include statement\n"));
00314 return RPMERR_BADSPEC;
00315 }
00316 *endFileName = '\0';
00317
00318 forceIncludeFile(spec, fileName);
00319
00320 ofi = spec->fileStack;
00321 goto retry;
00322 }
00323
00324 if (match != -1) {
00325 rl = xmalloc(sizeof(struct ReadLevelEntry));
00326 rl->reading = spec->readStack->reading && match;
00327 rl->next = spec->readStack;
00328 spec->readStack = rl;
00329 spec->line[0] = '\0';
00330 }
00331
00332 if (! spec->readStack->reading) {
00333 spec->line[0] = '\0';
00334 }
00335
00336 return 0;
00337 }
00338
00339 void closeSpec(Spec spec)
00340 {
00341 OFI_t *ofi;
00342
00343 while (spec->fileStack) {
00344 ofi = spec->fileStack;
00345 spec->fileStack = spec->fileStack->next;
00346 if (ofi->fd) Fclose(ofi->fd);
00347 FREE(ofi->fileName);
00348 free(ofi);
00349 }
00350 }
00351
00352 extern int noLang;
00353
00354 int parseSpec(Spec *specp, const char *specFile, const char *rootURL,
00355 const char *buildRootURL, int inBuildArch, const char *passPhrase,
00356 char *cookie, int anyarch, int force)
00357 {
00358 rpmParseState parsePart = PART_PREAMBLE;
00359 int initialPackage = 1;
00360 #ifdef DYING
00361 const char *saveArch;
00362 #endif
00363 Package pkg;
00364 int x, index;
00365 Spec spec;
00366
00367
00368 spec = newSpec();
00369
00370
00371
00372
00373
00374
00375
00376
00377 spec->specFile = rpmGetPath(specFile, NULL);
00378 spec->fileStack = newOpenFileInfo();
00379 spec->fileStack->fileName = xstrdup(spec->specFile);
00380 if (buildRootURL) {
00381 const char * buildRoot;
00382 (void) urlPath(buildRootURL, &buildRoot);
00383 if (*buildRoot == '\0') buildRoot = "/";
00384 if (!strcmp(buildRoot, "/")) {
00385 rpmError(RPMERR_BADSPEC,
00386 _("BuildRoot can not be \"/\": %s\n"), buildRootURL);
00387 return RPMERR_BADSPEC;
00388 }
00389 spec->gotBuildRootURL = 1;
00390 spec->buildRootURL = xstrdup(buildRootURL);
00391 addMacro(spec->macros, "buildroot", NULL, buildRoot, RMIL_SPEC);
00392 if (_debug)
00393 fprintf(stderr, "*** PS buildRootURL(%s) %p macro set to %s\n", spec->buildRootURL, spec->buildRootURL, buildRoot);
00394 }
00395 addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
00396 spec->inBuildArchitectures = inBuildArch;
00397 spec->anyarch = anyarch;
00398 spec->force = force;
00399
00400 if (rootURL)
00401 spec->rootURL = xstrdup(rootURL);
00402 if (passPhrase)
00403 spec->passPhrase = xstrdup(passPhrase);
00404 if (cookie)
00405 spec->cookie = xstrdup(cookie);
00406
00407 spec->timeCheck = rpmExpandNumeric("%{_timecheck}");
00408
00409
00410
00411
00412
00413 while (parsePart < PART_LAST && parsePart != PART_NONE) {
00414 switch (parsePart) {
00415 case PART_PREAMBLE:
00416 parsePart = parsePreamble(spec, initialPackage);
00417 initialPackage = 0;
00418 break;
00419 case PART_PREP:
00420 parsePart = parsePrep(spec);
00421 break;
00422 case PART_BUILD:
00423 case PART_INSTALL:
00424 case PART_CLEAN:
00425 parsePart = parseBuildInstallClean(spec, parsePart);
00426 break;
00427 case PART_CHANGELOG:
00428 parsePart = parseChangelog(spec);
00429 break;
00430 case PART_DESCRIPTION:
00431 parsePart = parseDescription(spec);
00432 break;
00433
00434 case PART_PRE:
00435 case PART_POST:
00436 case PART_PREUN:
00437 case PART_POSTUN:
00438 case PART_VERIFYSCRIPT:
00439 case PART_TRIGGERIN:
00440 case PART_TRIGGERUN:
00441 case PART_TRIGGERPOSTUN:
00442 parsePart = parseScript(spec, parsePart);
00443 break;
00444
00445 case PART_FILES:
00446 parsePart = parseFiles(spec);
00447 break;
00448
00449 case PART_NONE:
00450 case PART_LAST:
00451 case PART_BUILDARCHITECTURES:
00452 break;
00453 }
00454
00455 if (parsePart >= PART_LAST) {
00456 freeSpec(spec);
00457 return parsePart;
00458 }
00459
00460 if (parsePart == PART_BUILDARCHITECTURES) {
00461 spec->buildArchitectureSpecs =
00462 xmalloc(sizeof(Spec) * spec->buildArchitectureCount);
00463 index = 0;
00464 for (x = 0; x < spec->buildArchitectureCount; x++) {
00465 if (rpmMachineScore(RPM_MACHTABLE_BUILDARCH,
00466 spec->buildArchitectures[x])) {
00467 #ifdef DYING
00468 rpmGetMachine(&saveArch, NULL);
00469 saveArch = xstrdup(saveArch);
00470 rpmSetMachine(spec->buildArchitectures[x], NULL);
00471 #else
00472 addMacro(NULL, "_target_cpu", NULL, spec->buildArchitectures[x], RMIL_RPMRC);
00473 #endif
00474 if (parseSpec(&(spec->buildArchitectureSpecs[index]),
00475 specFile, spec->rootURL, buildRootURL, 1,
00476 passPhrase, cookie, anyarch, force)) {
00477 spec->buildArchitectureCount = index;
00478 freeSpec(spec);
00479 return RPMERR_BADSPEC;
00480 }
00481 #ifdef DYING
00482 rpmSetMachine(saveArch, NULL);
00483 free((void *)saveArch);
00484 #else
00485 delMacro(NULL, "_target_cpu");
00486 #endif
00487 index++;
00488 }
00489 }
00490 spec->buildArchitectureCount = index;
00491 if (! index) {
00492 freeSpec(spec);
00493 rpmError(RPMERR_BADSPEC, _("No buildable architectures\n"));
00494 return RPMERR_BADSPEC;
00495 }
00496
00497
00498
00499
00500
00501
00502
00503 if (spec->sl && spec->st) {
00504 Spec nspec = *spec->buildArchitectureSpecs;
00505 struct speclines *sl = spec->sl;
00506 struct spectags *st = spec->st;
00507 spec->sl = nspec->sl;
00508 spec->st = nspec->st;
00509 nspec->sl = sl;
00510 nspec->st = st;
00511 }
00512
00513 closeSpec(spec);
00514 *specp = spec;
00515 return 0;
00516 }
00517 }
00518
00519
00520 {
00521 #ifdef DYING
00522 const char *arch = NULL;
00523 const char *os = NULL;
00524 char *myos = NULL;
00525
00526 rpmGetArchInfo(&arch, NULL);
00527 rpmGetOsInfo(&os, NULL);
00528
00529
00530
00531
00532
00533
00534 if (!strcmp(os, "linux")) {
00535 myos = xstrdup(os);
00536 *myos = 'L';
00537 os = myos;
00538 }
00539 #else
00540 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00541 const char *os = rpmExpand("%{_target_os}", NULL);
00542 #endif
00543
00544 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
00545 if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) {
00546 const char * name;
00547 headerNVR(pkg->header, &name, NULL, NULL);
00548 rpmError(RPMERR_BADSPEC, _("Package has no %%description: %s\n"),
00549 name);
00550 freeSpec(spec);
00551 return RPMERR_BADSPEC;
00552 }
00553
00554 headerAddEntry(pkg->header, RPMTAG_OS, RPM_STRING_TYPE, os, 1);
00555 headerAddEntry(pkg->header, RPMTAG_ARCH, RPM_STRING_TYPE, arch, 1);
00556 }
00557 #ifdef DYING
00558 FREE(myos);
00559 #else
00560 free((void *)arch);
00561 free((void *)os);
00562 #endif
00563 }
00564
00565 closeSpec(spec);
00566 *specp = spec;
00567
00568 return 0;
00569 }