Remove opkg_internal_use_only and fix associated assumptions RE pkg->provides.
[oweals/opkg-lede.git] / libopkg / pkg_parse.c
1 /* pkg_parse.c - the opkg package management system
2
3    Steven M. Ayer
4    
5    Copyright (C) 2002 Compaq Computer Corporation
6
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2, or (at
10    your option) any later version.
11
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 */
17
18 #include "includes.h"
19 #include <errno.h>
20 #include <ctype.h>
21    
22 #include "pkg.h"
23 #include "opkg_utils.h"
24 #include "pkg_parse.h"
25 #include "libbb/libbb.h"
26
27 int isGenericFieldType(char * type, char * line)
28 {
29     if(!strncmp(line, type, strlen(type)))
30         return 1;
31     return 0;
32 }
33
34 char * parseGenericFieldType(char * type, char * raw)
35 {
36     char * field_value = raw + (strlen(type) + 1);
37     return trim_alloc(field_value);
38 }
39
40 void parseStatus(pkg_t *pkg, char * raw)
41 {
42     char sw_str[64], sf_str[64], ss_str[64];
43
44     sscanf(raw, "Status: %s %s %s", sw_str, sf_str, ss_str);
45     pkg->state_want = pkg_state_want_from_str(sw_str);
46     pkg->state_flag = pkg_state_flag_from_str(sf_str);
47     pkg->state_status = pkg_state_status_from_str(ss_str);
48 }
49
50 char ** parseDependsString(char * raw, int * depends_count)
51 {
52     char ** depends = NULL;
53     int line_count = 0;
54     char buff[2048], * dest;
55
56     while(raw && *raw && !isspace(*raw)) {
57         raw++;
58     }
59
60     if(line_is_blank(raw)){
61         *depends_count = line_count;
62         return NULL;
63     }
64     while(raw && *raw){
65         depends = xrealloc(depends, sizeof(char *) * (line_count + 1));
66         
67         while(isspace(*raw)) raw++;
68
69         dest = buff;
70         while((*raw != ',') && *raw)
71             *dest++ = *raw++;
72
73         *dest = '\0';
74         depends[line_count] = trim_alloc(buff);
75         if(depends[line_count] ==NULL)
76            return NULL;
77         line_count++;
78         if(*raw == ',')
79             raw++;
80     }
81     *depends_count = line_count;
82     return depends;
83 }
84
85 void parseConffiles(pkg_t * pkg, char * raw)
86 {
87     char file_name[1048], md5sum[1048];  /* please tell me there aren't any longer that 1k */
88
89     if(!strncmp(raw, "Conffiles:", 10))
90         raw += strlen("Conffiles:");
91
92     while(*raw && (sscanf(raw, "%s%s", file_name, md5sum) == 2)){
93         conffile_list_append(&pkg->conffiles, file_name, md5sum);
94         /*      fprintf(stderr, "%s %s ", file_name, md5sum);*/
95         while (*raw && isspace(*raw)) {
96             raw++;
97         }
98         raw += strlen(file_name);
99         while (*raw && isspace(*raw)) {
100             raw++;
101         }
102         raw += strlen(md5sum);
103     }
104 }    
105
106 int parseVersion(pkg_t *pkg, char *raw)
107 {
108   char *colon, *eepochcolon;
109   char *hyphen;
110   unsigned long epoch;
111
112   if (!*raw) {
113       fprintf(stderr, "%s: ERROR: version string is empty", __FUNCTION__);
114       return EINVAL;
115   }
116
117   if (strncmp(raw, "Version:", 8) == 0) {
118       raw += 8;
119   }
120   while (*raw && isspace(*raw)) {
121       raw++;
122   }
123   
124   colon= strchr(raw,':');
125   if (colon) {
126     epoch= strtoul(raw,&eepochcolon,10);
127     if (colon != eepochcolon) {
128         fprintf(stderr, "%s: ERROR: epoch in version is not number", __FUNCTION__);
129         return EINVAL;
130     }
131     if (!*++colon) {
132         fprintf(stderr, "%s: ERROR: nothing after colon in version number", __FUNCTION__);
133         return EINVAL;
134     }
135     raw= colon;
136     pkg->epoch= epoch;
137   } else {
138     pkg->epoch= 0;
139   }
140
141   pkg->revision = "";
142
143   if (!pkg->version)
144   {
145     pkg->version= xcalloc(1, strlen(raw)+1);
146     strcpy(pkg->version, raw);
147   }
148
149   hyphen= strrchr(pkg->version,'-');
150
151   if (hyphen) {
152     *hyphen++= 0;
153       pkg->revision = hyphen;
154   }
155
156   return 0;
157 }
158
159 /* Some random thoughts from Carl:
160
161    This function could be considerably simplified if we just kept
162    an array of all the generic string-valued field names, and looped
163    through those looking for a match. Also, these fields could perhaps
164    be stored in the package as an array as well, (or, probably better,
165    as an nv_pair_list_t).
166
167    Fields which require special parsing or storage, (such as Depends:
168    and Status:) could be handled as they are now. 
169 */
170 /* XXX: FEATURE: The Suggests: field needs to be changed from a string
171    to a dependency list. And, since we already have
172    Depends/Pre-Depends and need to add Conflicts, Recommends, and
173    Enhances, perhaps we could generalize all of these and save some
174    code duplication.
175 */
176 int pkg_parse_raw(pkg_t *pkg, char ***raw, pkg_src_t *src, pkg_dest_t *dest)
177 {
178     int reading_conffiles, reading_description;
179     char ** lines;
180
181     pkg->src = src;
182     pkg->dest = dest;
183
184     reading_conffiles = reading_description = 0;
185
186     for (lines = *raw; *lines; lines++) {
187         /*      fprintf(stderr, "PARSING %s\n", *lines);*/
188         switch (**lines) {
189         case 'P':
190             if(isGenericFieldType("Package:", *lines)) 
191                 pkg->name = parseGenericFieldType("Package", *lines);
192             else if(isGenericFieldType("Priority:", *lines))
193                 pkg->priority = parseGenericFieldType("Priority", *lines);
194             else if(isGenericFieldType("Provides", *lines)){
195                 pkg->provides_str = parseDependsString(*lines, &pkg->provides_count);
196             } 
197             else if(isGenericFieldType("Pre-Depends", *lines))
198                 pkg->pre_depends_str = parseDependsString(*lines, &pkg->pre_depends_count);
199             break;
200
201         case 'A':
202             if(isGenericFieldType("Architecture:", *lines))
203                 pkg->architecture = parseGenericFieldType("Architecture", *lines);
204             else if(isGenericFieldType("Auto-Installed:", *lines)) {
205                 char *auto_installed_value;
206                 auto_installed_value = parseGenericFieldType("Auto-Installed:", *lines);
207                 if (strcmp(auto_installed_value, "yes") == 0) {
208                     pkg->auto_installed = 1;
209                 }
210                 free(auto_installed_value);
211             }
212             break;
213
214         case 'F':
215             if(isGenericFieldType("Filename:", *lines))
216                 pkg->filename = parseGenericFieldType("Filename", *lines);
217             break;
218
219         case 'S':
220             if(isGenericFieldType("Section:", *lines))
221                 pkg->section = parseGenericFieldType("Section", *lines);
222 #ifdef HAVE_SHA256
223             else if(isGenericFieldType("SHA256sum:", *lines))
224                 pkg->sha256sum = parseGenericFieldType("SHA256sum", *lines);
225 #endif
226             else if(isGenericFieldType("Size:", *lines))
227                 pkg->size = parseGenericFieldType("Size", *lines);
228             else if(isGenericFieldType("Source:", *lines))
229                 pkg->source = parseGenericFieldType("Source", *lines);
230             else if(isGenericFieldType("Status", *lines))
231                 parseStatus(pkg, *lines);
232             else if(isGenericFieldType("Suggests", *lines))
233                 pkg->suggests_str = parseDependsString(*lines, &pkg->suggests_count);
234             break;
235
236         case 'T':
237             if(isGenericFieldType("Tags:", *lines))
238                 pkg->tags = parseGenericFieldType("Tags", *lines);
239             break;
240
241         case 'M':
242             if(isGenericFieldType("MD5sum:", *lines))
243                 pkg->md5sum = parseGenericFieldType("MD5sum", *lines);
244             /* The old opkg wrote out status files with the wrong case for MD5sum,
245                 let's parse it either way */
246             else if(isGenericFieldType("MD5Sum:", *lines))
247                 pkg->md5sum = parseGenericFieldType("MD5Sum", *lines);
248             else if(isGenericFieldType("Maintainer", *lines))
249                 pkg->maintainer = parseGenericFieldType("Maintainer", *lines);
250             break;
251
252         case 'I':
253             if(isGenericFieldType("Installed-Size:", *lines))
254                 pkg->installed_size = parseGenericFieldType("Installed-Size", *lines);
255             else if(isGenericFieldType("Installed-Time:", *lines)) {
256                 char *time_str = parseGenericFieldType("Installed-Time", *lines);
257                 pkg->installed_time = strtoul(time_str, NULL, 0);
258                 free (time_str);
259             }       
260             break;
261
262         case 'E':
263             if(isGenericFieldType("Essential:", *lines)) {
264                 char *essential_value;
265                 essential_value = parseGenericFieldType("Essential", *lines);
266                 if (strcmp(essential_value, "yes") == 0) {
267                     pkg->essential = 1;
268                 }
269                 free(essential_value);
270             }
271             break;
272
273         case 'V':
274             if(isGenericFieldType("Version", *lines))
275                 parseVersion(pkg, *lines);
276             break;
277
278         case 'C':
279             if(isGenericFieldType("Conffiles", *lines)){
280                 parseConffiles(pkg, *lines);
281                 reading_conffiles = 1;
282             }
283             else if(isGenericFieldType("Conflicts", *lines))
284                 pkg->conflicts_str = parseDependsString(*lines, &pkg->conflicts_count);
285             break;
286
287         case 'D':
288             if(isGenericFieldType("Description", *lines)) {
289                 pkg->description = parseGenericFieldType("Description", *lines);
290                 reading_conffiles = 0;
291                 reading_description = 1;
292             }
293             else if(isGenericFieldType("Depends", *lines))
294                 pkg->depends_str = parseDependsString(*lines, &pkg->depends_count);
295             break;
296
297         case 'R':
298             if(isGenericFieldType("Recommends", *lines))
299                 pkg->recommends_str = parseDependsString(*lines, &pkg->recommends_count);
300             else if(isGenericFieldType("Replaces", *lines))
301                 pkg->replaces_str = parseDependsString(*lines, &pkg->replaces_count);
302             
303             break;
304
305         case ' ':
306             if(reading_description) {
307                 /* we already know it's not blank, so the rest of description */      
308                 pkg->description = xrealloc(pkg->description,
309                                            strlen(pkg->description)
310                                            + 1 + strlen(*lines) + 1);
311                 strcat(pkg->description, "\n");
312                 strcat(pkg->description, (*lines));
313             }
314             else if(reading_conffiles)
315                 parseConffiles(pkg, *lines);
316                 
317             break;
318
319         default:
320             if(line_is_blank(*lines)) {
321                 lines++;
322                 goto out;
323             }
324         }
325     }
326 out:;
327     
328     *raw = lines;
329
330     if (pkg->name) {
331         return 0;
332     } else {
333         return EINVAL;
334     }
335 }
336
337 int pkg_valorize_other_field(pkg_t *pkg, char ***raw)
338 {
339     char ** lines;
340
341     for (lines = *raw; *lines; lines++) {
342         if(isGenericFieldType("Essential:", *lines)) {
343             char *essential_value;
344             essential_value = parseGenericFieldType("Essential", *lines);
345             if (strcmp(essential_value, "yes") == 0) {
346                 pkg->essential = 1;
347             }
348             free(essential_value);
349         }
350     }
351     *raw = lines;
352
353     return 0;
354 }