Splint fiddles.
[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, rpmTag tagN,
36                int index, rpmsenseFlags tagflags)
37 {
38     const char *r, *re, *v, *ve;
39     char * N, * EVR;
40     rpmsenseFlags Flags;
41     Header h;
42
43     switch (tagN) {
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 /*@-boundsread@*/
92     for (r = field; *r != '\0'; r = re) {
93         SKIPWHITE(r);
94         if (*r == '\0')
95             break;
96
97         Flags = (tagflags & ~RPMSENSE_SENSEMASK);
98
99         /* Tokens must begin with alphanumeric, _, or / */
100         if (!(xisalnum(r[0]) || r[0] == '_' || r[0] == '/')) {
101             rpmError(RPMERR_BADSPEC,
102                      _("line %d: Dependency tokens must begin with alpha-numeric, '_' or '/': %s\n"),
103                      spec->lineNum, spec->line);
104             return RPMERR_BADSPEC;
105         }
106
107         /* Don't permit file names as args for certain tags */
108         switch (tagN) {
109         case RPMTAG_OBSOLETEFLAGS:
110         case RPMTAG_CONFLICTFLAGS:
111         case RPMTAG_BUILDCONFLICTS:
112             if (r[0] == '/') {
113                 rpmError(RPMERR_BADSPEC,_("line %d: File name not permitted: %s\n"),
114                          spec->lineNum, spec->line);
115                 return RPMERR_BADSPEC;
116             }
117             /*@switchbreak@*/ break;
118         default:
119             /*@switchbreak@*/ break;
120         }
121
122         re = r;
123         SKIPNONWHITE(re);
124         N = xmalloc((re-r) + 1);
125         strncpy(N, r, (re-r));
126         N[re-r] = '\0';
127
128         /* Parse EVR */
129         v = re;
130         SKIPWHITE(v);
131         ve = v;
132         SKIPNONWHITE(ve);
133
134         re = v; /* ==> next token (if no EVR found) starts here */
135
136         /* Check for possible logical operator */
137         if (ve > v) {
138           struct ReqComp *rc;
139           for (rc = ReqComparisons; rc->token != NULL; rc++) {
140             if ((ve-v) != strlen(rc->token) || strncmp(v, rc->token, (ve-v)))
141                 /*@innercontinue@*/ continue;
142
143             if (r[0] == '/') {
144                 rpmError(RPMERR_BADSPEC,
145                          _("line %d: Versioned file name not permitted: %s\n"),
146                          spec->lineNum, spec->line);
147                 return RPMERR_BADSPEC;
148             }
149
150             switch(tagN) {
151             case RPMTAG_BUILDPREREQ:
152             case RPMTAG_PREREQ:
153             case RPMTAG_PROVIDEFLAGS:
154             case RPMTAG_OBSOLETEFLAGS:
155                 /* Add prereq on rpmlib that has versioned dependencies. */
156                 if (!rpmExpandNumeric("%{?_noVersionedDependencies}"))
157                     (void) rpmlibNeedsFeature(h, "VersionedDependencies", "3.0.3-1");
158                 /*@switchbreak@*/ break;
159             default:
160                 /*@switchbreak@*/ break;
161             }
162             Flags |= rc->sense;
163
164             /* now parse EVR */
165             v = ve;
166             SKIPWHITE(v);
167             ve = v;
168             SKIPNONWHITE(ve);
169             /*@innerbreak@*/ break;
170           }
171         }
172
173         /*@-branchstate@*/
174         if (Flags & RPMSENSE_SENSEMASK) {
175             if (*v == '\0' || ve == v) {
176                 rpmError(RPMERR_BADSPEC, _("line %d: Version required: %s\n"),
177                         spec->lineNum, spec->line);
178                 return RPMERR_BADSPEC;
179             }
180             EVR = xmalloc((ve-v) + 1);
181             strncpy(EVR, v, (ve-v));
182             EVR[ve-v] = '\0';
183             re = ve;    /* ==> next token after EVR string starts here */
184         } else
185             EVR = NULL;
186         /*@=branchstate@*/
187
188         (void) addReqProv(spec, h, tagN, N, EVR, Flags, index);
189
190         N = _free(N);
191         EVR = _free(EVR);
192
193     }
194 /*@=boundsread@*/
195
196     return 0;
197 }