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