/** * Split EVR into epoch, version, and release components. * @param evr [epoch:]version[-release] string * @retval *ep pointer to epoch * @retval *vp pointer to version * @retval *rp pointer to release */ static void parseEVR(char * evr, const char ** ep, const char ** vp, const char ** rp) { const char *epoch; const char *version; /* assume only version is present */ const char *release; char *s, *se; s = evr; while (*s && risdigit(*s)) s++; /* s points to epoch terminator */ se = strrchr(s, '-'); /* se points to version terminator */ if (*s == ':') { epoch = evr; *s++ = '\0'; version = s; if (*epoch == '\0') epoch = "0"; } else { epoch = NULL; /* XXX disable epoch compare if missing */ version = evr; } if (se) { *se++ = '\0'; release = se; } else { release = NULL; } if (ep) *ep = epoch; if (vp) *vp = version; if (rp) *rp = release; }
/** * Execute macro primitives. * @param mb macro expansion state * @param negate should logic be inverted? * @param f beginning of field f * @param fn length of field f * @param g beginning of field g * @param gn length of field g */ static void doFoo(MacroBuf mb, int negate, const char * f, size_t fn, const char * g, size_t gn) { size_t blen = MACROBUFSIZ + fn + gn; char *buf = xmalloc(blen); char *b = NULL, *be; int c; buf[0] = '\0'; if (g != NULL) { strncpy(buf, g, gn); buf[gn] = '\0'; (void) expandU(mb, buf, blen); } if (STREQ("basename", f, fn)) { if ((b = strrchr(buf, '/')) == NULL) b = buf; else b++; #if NOTYET /* XXX watchout for conflict with %dir */ } else if (STREQ("dirname", f, fn)) { if ((b = strrchr(buf, '/')) != NULL) *b = '\0'; b = buf; #endif } else if (STREQ("suffix", f, fn)) { if ((b = strrchr(buf, '.')) != NULL) b++; } else if (STREQ("expand", f, fn)) { b = buf; } else if (STREQ("verbose", f, fn)) { if (negate) b = (rpmIsVerbose() ? NULL : buf); else b = (rpmIsVerbose() ? buf : NULL); } else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) { (void)urlPath(buf, (const char **)&b); if (*b == '\0') b = "/"; } else if (STREQ("uncompress", f, fn)) { rpmCompressedMagic compressed = COMPRESSED_OTHER; for (b = buf; (c = *b) && isblank(c);) b++; for (be = b; (c = *be) && !isblank(c);) be++; *be++ = '\0'; (void) rpmFileIsCompressed(b, &compressed); switch(compressed) { default: case COMPRESSED_NOT: sprintf(be, "%%__cat %s", b); break; case COMPRESSED_OTHER: sprintf(be, "%%__gzip -dc %s", b); break; case COMPRESSED_BZIP2: sprintf(be, "%%__bzip2 -dc %s", b); break; case COMPRESSED_ZIP: sprintf(be, "%%__unzip %s", b); break; case COMPRESSED_LZMA: sprintf(be, "%%__lzma -dc %s", b); break; } b = be; } else if (STREQ("getenv", f, fn)) { b = getenv(buf); } else if (STREQ("S", f, fn)) { for (b = buf; (c = *b) && risdigit(c);) b++; if (!c) { /* digit index */ b++; sprintf(b, "%%SOURCE%s", buf); } else b = buf; } else if (STREQ("P", f, fn)) { for (b = buf; (c = *b) && risdigit(c);) b++; if (!c) { /* digit index */ b++; sprintf(b, "%%PATCH%s", buf); } else b = buf; } else if (STREQ("F", f, fn)) { b = buf + strlen(buf) + 1; sprintf(b, "file%s.file", buf); } if (b) { (void) expandT(mb, b, strlen(b)); } free(buf); }
/* -1: b is newer than a */ int rpmvercmp(const char * a, const char * b) { char oldch1, oldch2; char abuf[strlen(a)+1], bbuf[strlen(b)+1]; char *str1 = abuf, *str2 = bbuf; char * one, * two; int rc; int isnum; /* easy comparison to see if versions are identical */ if (rstreq(a, b)) return 0; strcpy(str1, a); strcpy(str2, b); one = str1; two = str2; /* loop through each version segment of str1 and str2 and compare them */ while (*one || *two) { while (*one && !risalnum(*one) && *one != '~') one++; while (*two && !risalnum(*two) && *two != '~') two++; /* handle the tilde separator, it sorts before everthing else */ if (*one == '~' || *two == '~') { if (*one != '~') return 1; if (*two != '~') return -1; one++; two++; continue; } /* If we ran to the end of either, we are finished with the loop */ if (!(*one && *two)) break; str1 = one; str2 = two; /* grab first completely alpha or completely numeric segment */ /* leave one and two pointing to the start of the alpha or numeric */ /* segment and walk str1 and str2 to end of segment */ if (risdigit(*str1)) { while (*str1 && risdigit(*str1)) str1++; while (*str2 && risdigit(*str2)) str2++; isnum = 1; } else { while (*str1 && risalpha(*str1)) str1++; while (*str2 && risalpha(*str2)) str2++; isnum = 0; } /* save character at the end of the alpha or numeric segment */ /* so that they can be restored after the comparison */ oldch1 = *str1; *str1 = '\0'; oldch2 = *str2; *str2 = '\0'; /* this cannot happen, as we previously tested to make sure that */ /* the first string has a non-null segment */ if (one == str1) return -1; /* arbitrary */ /* take care of the case where the two version segments are */ /* different types: one numeric, the other alpha (i.e. empty) */ /* numeric segments are always newer than alpha segments */ /* XXX See patch #60884 (and details) from bugzilla #50977. */ if (two == str2) return (isnum ? 1 : -1); if (isnum) { /* this used to be done by converting the digit segments */ /* to ints using atoi() - it's changed because long */ /* digit segments can overflow an int - this should fix that. */ /* throw away any leading zeros - it's a number, right? */ while (*one == '0') one++; while (*two == '0') two++; /* whichever number has more digits wins */ if (strlen(one) > strlen(two)) return 1; if (strlen(two) > strlen(one)) return -1; } /* strcmp will return which one is greater - even if the two */ /* segments are alpha or if they are numeric. don't return */ /* if they are equal because there might be more segments to */ /* compare */ rc = strcmp(one, two); if (rc) return (rc < 1 ? -1 : 1); /* restore character that was replaced by null above */ *str1 = oldch1; one = str1; *str2 = oldch2; two = str2; } /* this catches the case where all numeric and alpha segments have */ /* compared identically but the segment sepparating characters were */ /* different */ if ((!*one) && (!*two)) return 0; /* whichever version still has characters left over wins */ if (!*one) return -1; else return 1; }
/* keyp might no be defined. */ rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmDbiTagVal rpmtag, const void * keyp, size_t keylen) { rpmdbMatchIterator mi = NULL; char *tmp = NULL; if (ts == NULL) return NULL; if (ts && ts->keyring == NULL) loadKeyring(ts); if (ts->rdb == NULL && rpmtsOpenDB(ts, ts->dbmode)) return NULL; /* Parse out "N(EVR)" tokens from a label key if present */ if (rpmtag == RPMDBI_LABEL && keyp != NULL && strchr(keyp, '(')) { const char *se, *s = keyp; char *t; size_t slen = strlen(s); int level = 0; int c; tmp = xmalloc(slen+1); keyp = t = tmp; while ((c = *s++) != '\0') { switch (c) { default: *t++ = c; break; case '(': /* XXX Fail if nested parens. */ if (level++ != 0) { rpmlog(RPMLOG_ERR, _("extra '(' in package label: %s\n"), (const char*)keyp); goto exit; } /* Parse explicit epoch. */ for (se = s; *se && risdigit(*se); se++) {}; if (*se == ':') { /* XXX skip explicit epoch's (for now) */ *t++ = '-'; s = se + 1; } else { /* No Epoch: found. Convert '(' to '-' and chug. */ *t++ = '-'; } break; case ')': /* XXX Fail if nested parens. */ if (--level != 0) { rpmlog(RPMLOG_ERR, _("missing '(' in package label: %s\n"), (const char*)keyp); goto exit; } /* Don't copy trailing ')' */ break; } } if (level) { rpmlog(RPMLOG_ERR, _("missing ')' in package label: %s\n"), (const char*)keyp); goto exit; } *t = '\0'; } mi = rpmdbInitIterator(ts->rdb, rpmtag, keyp, keylen); /* Verify header signature/digest during retrieve (if not disabled). */ if (mi && !(ts->vsflags & RPMVSF_NOHDRCHK)) (void) rpmdbSetHdrChk(mi, ts, headerCheck); exit: free(tmp); return mi; }
/** * @param state expression parser state */ static int rdToken(ParseState state) { int token; Value v = NULL; char *p = state->p; /* Skip whitespace before the next token. */ while (*p && risspace(*p)) p++; switch (*p) { case '\0': token = TOK_EOF; p--; break; case '+': token = TOK_ADD; break; case '-': token = TOK_MINUS; break; case '*': token = TOK_MULTIPLY; break; case '/': token = TOK_DIVIDE; break; case '(': token = TOK_OPEN_P; break; case ')': token = TOK_CLOSE_P; break; case '=': if (p[1] == '=') { token = TOK_EQ; p++; } else { rpmlog(RPMLOG_ERR, _("syntax error while parsing ==\n")); return -1; } break; case '!': if (p[1] == '=') { token = TOK_NEQ; p++; } else token = TOK_NOT; break; case '<': if (p[1] == '=') { token = TOK_LE; p++; } else token = TOK_LT; break; case '>': if (p[1] == '=') { token = TOK_GE; p++; } else token = TOK_GT; break; case '&': if (p[1] == '&') { token = TOK_LOGICAL_AND; p++; } else { rpmlog(RPMLOG_ERR, _("syntax error while parsing &&\n")); return -1; } break; case '|': if (p[1] == '|') { token = TOK_LOGICAL_OR; p++; } else { rpmlog(RPMLOG_ERR, _("syntax error while parsing ||\n")); return -1; } break; default: if (risdigit(*p)) { char *temp; size_t ts; for (ts=1; p[ts] && risdigit(p[ts]); ts++); temp = xmalloc(ts+1); memcpy(temp, p, ts); p += ts-1; temp[ts] = '\0'; token = TOK_INTEGER; v = valueMakeInteger(atoi(temp)); free(temp); } else if (risalpha(*p)) { char *temp; size_t ts; for (ts=1; p[ts] && (risalnum(p[ts]) || p[ts] == '_'); ts++); temp = xmalloc(ts+1); memcpy(temp, p, ts); p += ts-1; temp[ts] = '\0'; token = TOK_IDENTIFIER; v = valueMakeString(temp); } else if (*p == '\"') { char *temp; size_t ts; p++; for (ts=0; p[ts] && p[ts] != '\"'; ts++); temp = xmalloc(ts+1); memcpy(temp, p, ts); p += ts-1; temp[ts] = '\0'; p++; token = TOK_STRING; v = valueMakeString( rpmExpand(temp, NULL) ); free(temp); } else { rpmlog(RPMLOG_ERR, _("parse error in expression\n")); return -1; } } state->p = p + 1; state->nextToken = token; state->tokenValue = v; DEBUG(printf("rdToken: \"%s\" (%d)\n", prToken(token), token)); DEBUG(valueDump("rdToken:", state->tokenValue, stdout)); return 0; }