1 /* pkg_parse.c - the itsy package management system
5 Copyright (C) 2002 Compaq Computer Corporation
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.
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.
23 #include "opkg_utils.h"
24 #include "pkg_parse.h"
26 int isGenericFieldType(char * type
, char * line
)
28 if(!strncmp(line
, type
, strlen(type
)))
33 char * parseGenericFieldType(char * type
, char * raw
)
35 char * field_value
= raw
+ (strlen(type
) + 1);
36 return trim_alloc(field_value
);
39 void parseStatus(pkg_t
*pkg
, char * raw
)
41 char sw_str
[64], sf_str
[64], ss_str
[64];
43 sscanf(raw
, "Status: %s %s %s", sw_str
, sf_str
, ss_str
);
44 pkg
->state_want
= pkg_state_want_from_str(sw_str
);
45 pkg
->state_flag
= pkg_state_flag_from_str(sf_str
);
46 pkg
->state_status
= pkg_state_status_from_str(ss_str
);
49 char ** parseDependsString(char * raw
, int * depends_count
)
51 char ** depends
= NULL
;
53 char buff
[2048], * dest
;
55 while(raw
&& *raw
&& !isspace(*raw
)) {
59 if(line_is_blank(raw
)){
60 *depends_count
= line_count
;
64 depends
= (char **)realloc(depends
, sizeof(char *) * (line_count
+ 1));
66 while(isspace(*raw
)) raw
++;
69 while((*raw
!= ',') && *raw
)
73 depends
[line_count
] = trim_alloc(buff
);
74 if(depends
[line_count
] ==NULL
)
80 *depends_count
= line_count
;
84 void parseConffiles(pkg_t
* pkg
, char * raw
)
86 char file_name
[1048], md5sum
[1048]; /* please tell me there aren't any longer that 1k */
88 if(!strncmp(raw
, "Conffiles:", 10))
89 raw
+= strlen("Conffiles:");
91 while(*raw
&& (sscanf(raw
, "%s%s", file_name
, md5sum
) == 2)){
92 conffile_list_append(&pkg
->conffiles
, file_name
, md5sum
);
93 /* fprintf(stderr, "%s %s ", file_name, md5sum);*/
94 while (*raw
&& isspace(*raw
)) {
97 raw
+= strlen(file_name
);
98 while (*raw
&& isspace(*raw
)) {
101 raw
+= strlen(md5sum
);
105 int parseVersion(pkg_t
*pkg
, char *raw
)
107 char *colon
, *eepochcolon
;
112 fprintf(stderr
, "%s: ERROR: version string is empty", __FUNCTION__
);
116 if (strncmp(raw
, "Version:", 8) == 0) {
119 while (*raw
&& isspace(*raw
)) {
123 colon
= strchr(raw
,':');
125 epoch
= strtoul(raw
,&eepochcolon
,10);
126 if (colon
!= eepochcolon
) {
127 fprintf(stderr
, "%s: ERROR: epoch in version is not number", __FUNCTION__
);
131 fprintf(stderr
, "%s: ERROR: nothing after colon in version number", __FUNCTION__
);
141 pkg
->familiar_revision
= "";
143 pkg
->version
= malloc(strlen(raw
)+1);
144 if ( pkg
->version
== NULL
) {
145 fprintf(stderr
, "%s: out of memory \n", __FUNCTION__
);
148 strcpy(pkg
->version
, raw
);
150 hyphen
= strrchr(pkg
->version
,'-');
154 pkg
->revision
= hyphen
;
158 fprintf(stderr,"Parsed version: %lu, %s, %s, %s\n",
162 pkg->familiar_revision);
169 /* This code is needed to insert in first position the keyword for the aligning bug */
171 int alterProvidesLine(char *raw
, char *temp
)
176 fprintf(stderr
, "%s: ERROR: Provides string is empty", __FUNCTION__
);
180 if ( temp
== NULL
) {
181 fprintf(stderr
, "%s: out of memory \n", __FUNCTION__
);
185 if (strncmp(raw
, "Provides:", 9) == 0) {
188 while (*raw
&& isspace(*raw
)) {
192 snprintf ( temp
, 35, "Provides: opkg_internal_use_only, "); /* First part of the line */
194 strncat( temp
, raw
++, 1);
200 /* Some random thoughts from Carl:
202 This function could be considerably simplified if we just kept
203 an array of all the generic string-valued field names, and looped
204 through those looking for a match. Also, these fields could perhaps
205 be stored in the package as an array as well, (or, probably better,
206 as an nv_pair_list_t).
208 Fields which require special parsing or storage, (such as Depends:
209 and Status:) could be handled as they are now.
211 /* XXX: FEATURE: The Suggests: field needs to be changed from a string
212 to a dependency list. And, since we already have
213 Depends/Pre-Depends and need to add Conflicts, Recommends, and
214 Enhances, perhaps we could generalize all of these and save some
217 int pkg_parse_raw(pkg_t
*pkg
, char ***raw
, pkg_src_t
*src
, pkg_dest_t
*dest
)
219 int reading_conffiles
, reading_description
;
220 int pkg_false_provides
=1;
227 reading_conffiles
= reading_description
= 0;
229 for (lines
= *raw
; *lines
; lines
++) {
230 /* fprintf(stderr, "PARSING %s\n", *lines);*/
233 if(isGenericFieldType("Package:", *lines
))
234 pkg
->name
= parseGenericFieldType("Package", *lines
);
235 else if(isGenericFieldType("Priority:", *lines
))
236 pkg
->priority
= parseGenericFieldType("Priority", *lines
);
237 else if(isGenericFieldType("Provides", *lines
)){
238 /* Here we add the internal_use to align the off by one problem between provides_str and provides */
239 provide
= (char * ) malloc(strlen(*lines
)+ 35 ); /* Preparing the space for the new opkg_internal_use_only */
240 if ( alterProvidesLine(*lines
,provide
) ){
243 pkg
->provides_str
= parseDependsString( provide
, &pkg
->provides_count
);
244 /* Let's try to hack a bit here.
245 The idea is that if a package has no Provides, we would add one generic, to permit the check of dependencies
246 in alot of other places. We will remove it before writing down the status database */
247 pkg_false_provides
=0;
250 else if(isGenericFieldType("Pre-Depends", *lines
))
251 pkg
->pre_depends_str
= parseDependsString(*lines
, &pkg
->pre_depends_count
);
255 if(isGenericFieldType("Architecture:", *lines
))
256 pkg
->architecture
= parseGenericFieldType("Architecture", *lines
);
257 else if(isGenericFieldType("Auto-Installed:", *lines
)) {
258 char *auto_installed_value
;
259 auto_installed_value
= parseGenericFieldType("Auto-Installed:", *lines
);
260 if (strcmp(auto_installed_value
, "yes") == 0) {
261 pkg
->auto_installed
= 1;
263 free(auto_installed_value
);
268 if(isGenericFieldType("Filename:", *lines
))
269 pkg
->filename
= parseGenericFieldType("Filename", *lines
);
273 if(isGenericFieldType("Section:", *lines
))
274 pkg
->section
= parseGenericFieldType("Section", *lines
);
275 else if(isGenericFieldType("Size:", *lines
))
276 pkg
->size
= parseGenericFieldType("Size", *lines
);
277 else if(isGenericFieldType("Source:", *lines
))
278 pkg
->source
= parseGenericFieldType("Source", *lines
);
279 else if(isGenericFieldType("Status", *lines
))
280 parseStatus(pkg
, *lines
);
281 else if(isGenericFieldType("Suggests", *lines
))
282 pkg
->suggests_str
= parseDependsString(*lines
, &pkg
->suggests_count
);
286 if(isGenericFieldType("Tags:", *lines
))
287 pkg
->tags
= parseGenericFieldType("Tags", *lines
);
291 if(isGenericFieldType("MD5sum:", *lines
))
292 pkg
->md5sum
= parseGenericFieldType("MD5sum", *lines
);
293 /* The old opkg wrote out status files with the wrong case for MD5sum,
294 let's parse it either way */
295 else if(isGenericFieldType("MD5Sum:", *lines
))
296 pkg
->md5sum
= parseGenericFieldType("MD5Sum", *lines
);
297 else if(isGenericFieldType("Maintainer", *lines
))
298 pkg
->maintainer
= parseGenericFieldType("Maintainer", *lines
);
302 if(isGenericFieldType("Installed-Size:", *lines
))
303 pkg
->installed_size
= parseGenericFieldType("Installed-Size", *lines
);
304 else if(isGenericFieldType("Installed-Time:", *lines
)) {
305 char *time_str
= parseGenericFieldType("Installed-Time", *lines
);
306 pkg
->installed_time
= strtoul(time_str
, NULL
, 0);
311 if(isGenericFieldType("Essential:", *lines
)) {
312 char *essential_value
;
313 essential_value
= parseGenericFieldType("Essential", *lines
);
314 if (strcmp(essential_value
, "yes") == 0) {
317 free(essential_value
);
322 if(isGenericFieldType("Version", *lines
))
323 parseVersion(pkg
, *lines
);
327 if(isGenericFieldType("Conffiles", *lines
)){
328 parseConffiles(pkg
, *lines
);
329 reading_conffiles
= 1;
331 else if(isGenericFieldType("Conflicts", *lines
))
332 pkg
->conflicts_str
= parseDependsString(*lines
, &pkg
->conflicts_count
);
336 if(isGenericFieldType("Description", *lines
)) {
337 pkg
->description
= parseGenericFieldType("Description", *lines
);
338 reading_conffiles
= 0;
339 reading_description
= 1;
341 else if(isGenericFieldType("Depends", *lines
))
342 pkg
->depends_str
= parseDependsString(*lines
, &pkg
->depends_count
);
346 if(isGenericFieldType("Recommends", *lines
))
347 pkg
->recommends_str
= parseDependsString(*lines
, &pkg
->recommends_count
);
348 else if(isGenericFieldType("Replaces", *lines
))
349 pkg
->replaces_str
= parseDependsString(*lines
, &pkg
->replaces_count
);
354 if(reading_description
) {
355 /* we already know it's not blank, so the rest of description */
356 pkg
->description
= realloc(pkg
->description
,
357 strlen(pkg
->description
)
358 + 1 + strlen(*lines
) + 1);
359 strcat(pkg
->description
, "\n");
360 strcat(pkg
->description
, (*lines
));
362 else if(reading_conffiles
)
363 parseConffiles(pkg
, *lines
);
368 if(line_is_blank(*lines
)) {
377 /* If the ipk has not a Provides line, we insert our false line */
378 if ( pkg_false_provides
==1)
379 pkg
->provides_str
= parseDependsString ((char *)"Provides: opkg_internal_use_only ", &pkg
->provides_count
);
388 int pkg_valorize_other_field(pkg_t
*pkg
, char ***raw
)
392 for (lines
= *raw
; *lines
; lines
++) {
393 if(isGenericFieldType("Essential:", *lines
)) {
394 char *essential_value
;
395 essential_value
= parseGenericFieldType("Essential", *lines
);
396 if (strcmp(essential_value
, "yes") == 0) {
399 free(essential_value
);