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 "ipkg_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;
108 #ifdef USE_DEBVERSION
114 fprintf(stderr, "%s: ERROR: version string is empty", __FUNCTION__);
118 if (strncmp(raw, "Version:", 8) == 0) {
121 while (*raw && isspace(*raw)) {
125 colon= strchr(raw,':');
127 epoch= strtoul(raw,&eepochcolon,10);
128 if (colon != eepochcolon) {
129 fprintf(stderr, "%s: ERROR: epoch in version is not number", __FUNCTION__);
133 fprintf(stderr, "%s: ERROR: nothing after colon in version number", __FUNCTION__);
143 pkg->familiar_revision = "";
145 pkg->version= malloc(strlen(raw)+1);
146 if ( pkg->version == NULL ) {
147 fprintf(stderr, "%s: out of memory \n", __FUNCTION__);
150 strcpy(pkg->version, raw);
152 #ifdef USE_DEBVERSION
153 hyphen= strrchr(pkg->version,'-');
157 if (strncmp("fam", hyphen, 3) == 0) {
158 pkg->familiar_revision=hyphen+3;
159 hyphen= strrchr(pkg->version,'-');
162 pkg->revision = hyphen;
165 pkg->revision = hyphen;
171 fprintf(stderr,"Parsed version: %lu, %s, %s, %s\n",
175 pkg->familiar_revision);
182 /* This code is needed to insert in first position the keyword for the aligning bug */
184 int alterProvidesLine(char *raw, char *temp)
189 fprintf(stderr, "%s: ERROR: Provides string is empty", __FUNCTION__);
193 if ( temp == NULL ) {
194 fprintf(stderr, "%s: out of memory \n", __FUNCTION__);
198 if (strncmp(raw, "Provides:", 9) == 0) {
201 while (*raw && isspace(*raw)) {
205 snprintf ( temp, 35, "Provides: ipkg_internal_use_only, "); /* First part of the line */
207 strncat( temp, raw++, 1);
213 /* Some random thoughts from Carl:
215 This function could be considerably simplified if we just kept
216 an array of all the generic string-valued field names, and looped
217 through those looking for a match. Also, these fields could perhaps
218 be stored in the package as an array as well, (or, probably better,
219 as an nv_pair_list_t).
221 Fields which require special parsing or storage, (such as Depends:
222 and Status:) could be handled as they are now.
224 /* XXX: FEATURE: The Suggests: field needs to be changed from a string
225 to a dependency list. And, since we already have
226 Depends/Pre-Depends and need to add Conflicts, Recommends, and
227 Enhances, perhaps we could generalize all of these and save some
230 int pkg_parse_raw(pkg_t *pkg, char ***raw, pkg_src_t *src, pkg_dest_t *dest)
232 int reading_conffiles, reading_description;
233 int pkg_false_provides=1;
240 reading_conffiles = reading_description = 0;
242 for (lines = *raw; *lines; lines++) {
243 /* fprintf(stderr, "PARSING %s\n", *lines);*/
244 if(isGenericFieldType("Package:", *lines))
245 pkg->name = parseGenericFieldType("Package", *lines);
246 else if(isGenericFieldType("Architecture:", *lines))
247 pkg->architecture = parseGenericFieldType("Architecture", *lines);
248 else if(isGenericFieldType("Filename:", *lines))
249 pkg->filename = parseGenericFieldType("Filename", *lines);
250 else if(isGenericFieldType("Section:", *lines))
251 pkg->section = parseGenericFieldType("Section", *lines);
252 else if(isGenericFieldType("MD5sum:", *lines))
253 pkg->md5sum = parseGenericFieldType("MD5sum", *lines);
254 /* The old ipkg wrote out status files with the wrong case for MD5sum,
255 let's parse it either way */
256 else if(isGenericFieldType("MD5Sum:", *lines))
257 pkg->md5sum = parseGenericFieldType("MD5Sum", *lines);
258 else if(isGenericFieldType("Size:", *lines))
259 pkg->size = parseGenericFieldType("Size", *lines);
260 else if(isGenericFieldType("Source:", *lines))
261 pkg->source = parseGenericFieldType("Source", *lines);
262 else if(isGenericFieldType("Installed-Size:", *lines))
263 pkg->installed_size = parseGenericFieldType("Installed-Size", *lines);
264 else if(isGenericFieldType("Installed-Time:", *lines)) {
265 char *time_str = parseGenericFieldType("Installed-Time", *lines);
266 pkg->installed_time = strtoul(time_str, NULL, 0);
267 } else if(isGenericFieldType("Priority:", *lines))
268 pkg->priority = parseGenericFieldType("Priority", *lines);
269 else if(isGenericFieldType("Essential:", *lines)) {
270 char *essential_value;
271 essential_value = parseGenericFieldType("Essential", *lines);
272 if (strcmp(essential_value, "yes") == 0) {
275 free(essential_value);
277 else if(isGenericFieldType("Status", *lines))
278 parseStatus(pkg, *lines);
279 else if(isGenericFieldType("Version", *lines))
280 parseVersion(pkg, *lines);
281 else if(isGenericFieldType("Maintainer", *lines))
282 pkg->maintainer = parseGenericFieldType("Maintainer", *lines);
283 else if(isGenericFieldType("Conffiles", *lines)){
284 parseConffiles(pkg, *lines);
285 reading_conffiles = 1;
287 else if(isGenericFieldType("Description", *lines)) {
288 pkg->description = parseGenericFieldType("Description", *lines);
289 reading_conffiles = 0;
290 reading_description = 1;
293 else if(isGenericFieldType("Provides", *lines)){
294 /* Here we add the internal_use to align the off by one problem between provides_str and provides */
295 provide = (char * ) malloc(strlen(*lines)+ 35 ); /* Preparing the space for the new ipkg_internal_use_only */
296 if ( alterProvidesLine(*lines,provide) ){
299 pkg->provides_str = parseDependsString( provide, &pkg->provides_count);
300 /* Let's try to hack a bit here.
301 The idea is that if a package has no Provides, we would add one generic, to permit the check of dependencies
302 in alot of other places. We will remove it before writing down the status database */
303 pkg_false_provides=0;
307 else if(isGenericFieldType("Depends", *lines))
308 pkg->depends_str = parseDependsString(*lines, &pkg->depends_count);
309 else if(isGenericFieldType("Pre-Depends", *lines))
310 pkg->pre_depends_str = parseDependsString(*lines, &pkg->pre_depends_count);
311 else if(isGenericFieldType("Recommends", *lines))
312 pkg->recommends_str = parseDependsString(*lines, &pkg->recommends_count);
313 else if(isGenericFieldType("Suggests", *lines))
314 pkg->suggests_str = parseDependsString(*lines, &pkg->suggests_count);
315 /* Abhaya: support for conflicts */
316 else if(isGenericFieldType("Conflicts", *lines))
317 pkg->conflicts_str = parseDependsString(*lines, &pkg->conflicts_count);
318 else if(isGenericFieldType("Replaces", *lines))
319 pkg->replaces_str = parseDependsString(*lines, &pkg->replaces_count);
320 else if(line_is_blank(*lines)) {
324 else if(**lines == ' '){
325 if(reading_description) {
326 /* we already know it's not blank, so the rest of description */
327 pkg->description = realloc(pkg->description,
328 strlen(pkg->description)
329 + 1 + strlen(*lines) + 1);
330 strcat(pkg->description, "\n");
331 strcat(pkg->description, (*lines));
333 else if(reading_conffiles)
334 parseConffiles(pkg, *lines);
338 /* If the ipk has not a Provides line, we insert our false line */
339 if ( pkg_false_provides==1)
340 pkg->provides_str = parseDependsString ((char *)"Provides: ipkg_internal_use_only ", &pkg->provides_count);
349 int pkg_valorize_other_field(pkg_t *pkg, char ***raw)
353 for (lines = *raw; *lines; lines++) {
354 if(isGenericFieldType("Essential:", *lines)) {
355 char *essential_value;
356 essential_value = parseGenericFieldType("Essential", *lines);
357 if (strcmp(essential_value, "yes") == 0) {
360 free(essential_value);