Explicit branchstate annotations.
[platform/upstream/rpm.git] / build / parseReqs.c
1 /** \ingroup rpmbuild
2  * \file build/parseReqs.c
3  *  Parse dependency tag from spec file or from auto-dependency generator.
4  */
5
6 #include "system.h"
7
8 #include "rpmbuild.h"
9 #include "debug.h"
10
11 /**
12  */
13 /*@observer@*/ /*@unchecked@*/
14 static struct ReqComp {
15 /*@observer@*/ /*@null@*/ const char * token;
16     rpmsenseFlags sense;
17 } ReqComparisons[] = {
18     { "<=", RPMSENSE_LESS | RPMSENSE_EQUAL},
19     { "=<", RPMSENSE_LESS | RPMSENSE_EQUAL},
20     { "<", RPMSENSE_LESS},
21
22     { "==", RPMSENSE_EQUAL},
23     { "=", RPMSENSE_EQUAL},
24     
25     { ">=", RPMSENSE_GREATER | RPMSENSE_EQUAL},
26     { "=>", RPMSENSE_GREATER | RPMSENSE_EQUAL},
27     { ">", RPMSENSE_GREATER},
28
29     { NULL, 0 },
30 };
31
32 #define SKIPWHITE(_x)   {while(*(_x) && (xisspace(*_x) || *(_x) == ',')) (_x)++;}
33 #define SKIPNONWHITE(_x){while(*(_x) &&!(xisspace(*_x) || *(_x) == ',')) (_x)++;}
34
35 int parseRCPOT(Spec spec, Package pkg, const char *field, int tag,
36                int index, rpmsenseFlags tagflags)
37 {
38     const char *r, *re, *v, *ve;
39     char * req, * version;
40     Header h;
41     rpmsenseFlags flags;
42
43     switch (tag) {
44     case RPMTAG_PROVIDEFLAGS:
45         tagflags |= RPMSENSE_PROVIDES;
46         h = pkg->header;
47         break;
48     case RPMTAG_OBSOLETEFLAGS:
49         tagflags |= RPMSENSE_OBSOLETES;
50         h = pkg->header;
51         break;
52     case RPMTAG_CONFLICTFLAGS:
53         tagflags |= RPMSENSE_CONFLICTS;
54         h = pkg->header;
55         break;
56     case RPMTAG_BUILDCONFLICTS:
57         tagflags |= RPMSENSE_CONFLICTS;
58         h = spec->buildRestrictions;
59         break;
60     case RPMTAG_PREREQ:
61         tagflags |= RPMSENSE_PREREQ;
62         h = pkg->header;
63         break;
64     case RPMTAG_BUILDPREREQ:
65         tagflags |= RPMSENSE_PREREQ;
66         h = spec->buildRestrictions;
67         break;
68     case RPMTAG_TRIGGERIN:
69         tagflags |= RPMSENSE_TRIGGERIN;
70         h = pkg->header;
71         break;
72     case RPMTAG_TRIGGERPOSTUN:
73         tagflags |= RPMSENSE_TRIGGERPOSTUN;
74         h = pkg->header;
75         break;
76     case RPMTAG_TRIGGERUN:
77         tagflags |= RPMSENSE_TRIGGERUN;
78         h = pkg->header;
79         break;
80     case RPMTAG_BUILDREQUIRES:
81         tagflags |= RPMSENSE_ANY;
82         h = spec->buildRestrictions;
83         break;
84     default:
85     case RPMTAG_REQUIREFLAGS:
86         tagflags |= RPMSENSE_ANY;
87         h = pkg->header;
88         break;
89     }
90
91     for (r = field; *r != '\0'; r = re) {
92         SKIPWHITE(r);
93         if (*r == '\0')
94             break;
95
96         flags = (tagflags & ~RPMSENSE_SENSEMASK);
97
98         /* Tokens must begin with alphanumeric, _, or / */
99         if (!(xisalnum(r[0]) || r[0] == '_' || r[0] == '/')) {
100             rpmError(RPMERR_BADSPEC,
101                      _("line %d: Dependency tokens must begin with alpha-numeric, '_' or '/': %s\n"),
102                      spec->lineNum, spec->line);
103             return RPMERR_BADSPEC;
104         }
105
106         /* Don't permit file names as args for certain tags */
107         switch (tag) {
108         case RPMTAG_OBSOLETEFLAGS:
109         case RPMTAG_CONFLICTFLAGS:
110         case RPMTAG_BUILDCONFLICTS:
111             if (r[0] == '/') {
112                 rpmError(RPMERR_BADSPEC,_("line %d: File name not permitted: %s\n"),
113                          spec->lineNum, spec->line);
114                 return RPMERR_BADSPEC;
115             }
116             /*@switchbreak@*/ break;
117         default:
118             /*@switchbreak@*/ break;
119         }
120
121         re = r;
122         SKIPNONWHITE(re);
123         req = xmalloc((re-r) + 1);
124         strncpy(req, r, (re-r));
125         req[re-r] = '\0';
126
127         /* Parse version */
128         v = re;
129         SKIPWHITE(v);
130         ve = v;
131         SKIPNONWHITE(ve);
132
133         re = v; /* ==> next token (if no version found) starts here */
134
135         /* Check for possible logical operator */
136         if (ve > v) {
137           struct ReqComp *rc;
138           for (rc = ReqComparisons; rc->token != NULL; rc++) {
139             if ((ve-v) != strlen(rc->token) || strncmp(v, rc->token, (ve-v)))
140                 /*@innercontinue@*/ continue;
141
142             if (r[0] == '/') {
143                 rpmError(RPMERR_BADSPEC,
144                          _("line %d: Versioned file name not permitted: %s\n"),
145                          spec->lineNum, spec->line);
146                 return RPMERR_BADSPEC;
147             }
148
149             switch(tag) {
150             case RPMTAG_BUILDPREREQ:
151             case RPMTAG_PREREQ:
152             case RPMTAG_PROVIDEFLAGS:
153             case RPMTAG_OBSOLETEFLAGS:
154                 /* Add prereq on rpmlib that has versioned dependencies. */
155                 if (!rpmExpandNumeric("%{_noVersionedDependencies}"))
156                     (void) rpmlibNeedsFeature(h, "VersionedDependencies", "3.0.3-1");
157                 /*@switchbreak@*/ break;
158             default:
159                 /*@switchbreak@*/ break;
160             }
161             flags |= rc->sense;
162
163             /* now parse version */
164             v = ve;
165             SKIPWHITE(v);
166             ve = v;
167             SKIPNONWHITE(ve);
168             /*@innerbreak@*/ break;
169           }
170         }
171
172         /*@-branchstate@*/
173         if (flags & RPMSENSE_SENSEMASK) {
174             if (*v == '\0' || ve == v) {
175                 rpmError(RPMERR_BADSPEC, _("line %d: Version required: %s\n"),
176                         spec->lineNum, spec->line);
177                 return RPMERR_BADSPEC;
178             }
179             version = xmalloc((ve-v) + 1);
180             strncpy(version, v, (ve-v));
181             version[ve-v] = '\0';
182             re = ve;    /* ==> next token after version string starts here */
183         } else
184             version = NULL;
185         /*@=branchstate@*/
186
187         (void) addReqProv(spec, h, flags, req, version, index);
188
189         req = _free(req);
190         version = _free(version);
191
192     }
193
194     return 0;
195 }