/* * rpmdata.c : handle the data in the RPM database. * * Copyright (c) 1997 Daniel Veillard * See COPYING for the status of this software. * * $Id: rpmdata.c,v 1.19 1998/03/17 19:27:04 veillard Exp $ */ #include #include #include #ifdef HAVE_FCNTL_H #include #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include "rpmdata.h" /* * An hash table for the RPM list */ #define HASH_SIZE 256 rpmDataPtr rpmHashTable[HASH_SIZE]; /* * the lists of RPM and resources collected so far. */ rpmDataPtr rpmList = NULL; rpmDataPtr rpmInstalledList = NULL; rpmDataPtr rpmSoftwareList = NULL; rpmRessPtr ressList = NULL; rpmRessPtr ressInstalledList = NULL; rpmArchPtr archList = NULL; rpmDirPtr dirList = NULL; rpmSubdirPtr dirTree = NULL; /* * Hash table initialization. */ static int rpmHashInitialized = 0; void rpmHashInitialize(void) { int i; for (i = 0; i < HASH_SIZE; i++) { rpmHashTable[i] = NULL; } rpmHashInitialized = 1; } /* * Compute an hash key, seems of for < 256 hash entries. */ int rpmGetHash(const char *name, const char *version, const char *release) { unsigned char res = 0; while (*name != 0) res += *(name++); while (*version != 0) res += *(version++); while (*release != 0) res += *(release++); return((int) (res % HASH_SIZE)); } /* * Insert a new RPM, managing the list of various software. */ void rpmAddSoftware(rpmDataPtr rpm) { rpmDataPtr cur; int hash; if (!rpmHashInitialized) rpmHashInitialize(); hash = rpmGetHash(rpm->name, rpm->version, rpm->release); cur = rpmHashTable[hash]; while (cur != NULL) { if (!strcmp(rpm->name, cur->name) && !strcmp(rpm->version, cur->version) && !strcmp(rpm->release, cur->release)) { /* * this is already in the sofware list, link in as * a new arch support. */ #ifdef DEBUG_HASH fprintf(stderr, "clash : (%d) %s-%s-%s.%s and %s-%s-%s.%s\n", hash, rpm->name, rpm->version, rpm->release, rpm->arch, cur->name, cur->version, cur->release, cur->arch); #endif rpm->nextArch = cur->nextArch; cur->nextArch = rpm; rpm->nextSoft = NULL; /* this one is not in the software list */ return; } cur = cur->nextHash; } /* * this wasn't found in the software list ! */ #ifdef DEBUG_HASH fprintf(stderr, "new : (%d) %s-%s-%s.%s\n", hash, rpm->name, rpm->version, rpm->release, rpm->arch); #endif rpm->nextHash = rpmHashTable[hash]; rpmHashTable[hash] = rpm; rpm->nextArch = NULL; rpm->nextSoft = rpmSoftwareList; rpmSoftwareList = rpm; } /* * Add a resource to the list if it doesn't exists and add the * corresponding RPM as a provider. */ rpmRessPtr rpmRessAdd(char *ress, rpmDataPtr rpm, int installed) { rpmRessPtr cur; if (installed) cur = ressInstalledList; else cur = ressList; /* search for the resource */ while (cur != NULL) { if (!strcmp(ress, cur->name)) goto found; cur = cur->next; } /* not found allocate a new resource block and fill it */ cur = (rpmRessPtr) malloc(sizeof(rpmRess)); memset(cur, 0, sizeof(rpmRess)); if (cur == NULL) { fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmRess), strerror(errno)); return(NULL); } cur->name = strdup(ress); cur->nb_provider = 0; cur->stamp = rpm->stamp; if (installed) { cur->next = ressInstalledList; ressInstalledList = cur; } else { cur->next = ressList; ressList = cur; } found: /* add the provider to the array */ if (cur->nb_provider >= MAX_PROVIDE) { fprintf(stderr, "MAX_PROVIDE %d overflow, increase the limit!\n", MAX_PROVIDE); return(NULL); } cur->provider[cur->nb_provider++] = rpm; if (rpm->stamp > cur->stamp) cur->stamp = rpm->stamp; return(cur); } /* * Add a resource to the list if it doesn't exists and add the * corresponding RPM as a requester. */ rpmRessPtr rpmRequAdd(char *requ, rpmDataPtr rpm, int installed) { rpmRessPtr cur; if (installed) cur = ressInstalledList; else cur = ressList; /* search for the resource */ while (cur != NULL) { if (!strcmp(requ, cur->name)) goto found; cur = cur->next; } /* not found allocate a new resource block and fill it */ cur = (rpmRessPtr) malloc(sizeof(rpmRess)); memset(cur, 0, sizeof(rpmRess)); if (cur == NULL) { fprintf(stderr, "cannot allocate %d bytes: %s\n", sizeof(rpmRess), strerror(errno)); return(NULL); } cur->name = strdup(requ); cur->nb_provider = 0; cur->stamp = rpm->stamp; if (installed) { cur->next = ressInstalledList; ressInstalledList = cur; } else { cur->next = ressList; ressList = cur; } found: if (rpm->stamp > cur->stamp) cur->stamp = rpm->stamp; return(cur); } /* * print an RPM data block */ void rpmDataPrint(rpmDataPtr rpm) { int i; printf("%s\n", rpm->filename); printf("%s-%s-%s\n", rpm->name, rpm->version, rpm->release); if (rpm->summary) printf(" %s\n", rpm->summary); for (i = 0; i < rpm->nb_resources ;i++) printf("-> %s\n", rpm->resources[i]->name); } /* * Add two RPM lists */ rpmDataPtr rpmAddList(rpmDataPtr ret, rpmDataPtr cur) { rpmDataPtr tmp; if (ret == NULL) return (cur); if (cur == NULL) return (ret); if (cur->next == NULL) { cur->next = ret; return(cur); } if (ret->next == NULL) { ret->next = cur; return(ret); } tmp = ret; while (tmp->next != NULL) tmp = tmp->next; tmp->next = cur; return(ret); } /* * A generic sort function for the full list. */ typedef int (*rpmCmpFunc)(rpmDataPtr a, rpmDataPtr b); rpmDataPtr rpmGenericSort(rpmCmpFunc rpmCmp, rpmDataPtr list, int installed) { rpmDataPtr unsorted; rpmDataPtr cur, prev; rpmDataPtr *base = &list; unsorted = *base; *base = NULL; while (unsorted != NULL) { cur = unsorted; unsorted = cur->next; cur->next = NULL; if ((*base == NULL) || (rpmCmp(cur, *base) < 0)) { cur->next = *base; *base = cur; } else { prev = *base; while ((prev->next != NULL) && ((rpmCmp(cur, prev->next) >= 0))) { prev = prev->next; } cur->next = prev->next; prev->next = cur; } } return(*base); } /* * A generic sort function for the software list. */ void rpmGenericSortSoftware(rpmCmpFunc rpmCmp, int installed) { rpmDataPtr unsorted; rpmDataPtr cur, prev; rpmDataPtr *base; base = &rpmSoftwareList; unsorted = *base; *base = NULL; while (unsorted != NULL) { /* * Extract the next element in the unsorted list. */ cur = unsorted; unsorted = cur->nextSoft; cur->nextSoft = NULL; if (*base == NULL) { *base = cur; } else if (rpmCmp(cur, *base) < 0) { cur->nextSoft = *base; *base = cur; } else { prev = *base; while ((prev->nextSoft != NULL) && ((rpmCmp(cur, prev->nextSoft) >= 0))) { prev = prev->nextSoft; } cur->nextSoft = prev->nextSoft; prev->nextSoft = cur; } } } /* * rpmGroupCmp : comparison of groupe values, if equal, compare * the names. */ int rpmGroupCmp(rpmDataPtr a, rpmDataPtr b) { int res = strcmp(a->group, b->group); if (res) return(res); res = strcmp(a->name, b->name); return(res); } /* * sort all the RPMs by Group. */ rpmDataPtr rpmGroupSort(rpmDataPtr list, int installed) { rpmDataPtr res; res = rpmGenericSort(rpmGroupCmp, list, installed); rpmGenericSortSoftware(rpmGroupCmp, installed); return(res); } /* * rpmDistribCmp : comparison of distributions values, if equal, compare * the names. */ int rpmDistribCmp(rpmDataPtr a, rpmDataPtr b) { int res = strcmp(a->distribution, b->distribution); if (res) return(res); res = strcmp(a->name, b->name); return(res); } /* * sort all the RPMs by Distribution. */ rpmDataPtr rpmDistribSort(rpmDataPtr list, int installed) { rpmDataPtr res; res = rpmGenericSort(rpmDistribCmp, list, installed); return(res); } /* * rpmVendorCmp : comparison of vendor values, if equal, compare * distributions, then compares the names. */ int rpmVendorCmp(rpmDataPtr a, rpmDataPtr b) { int res = strcmp(a->vendor, b->vendor); if (res) return(res); res = strcmp(a->distribution, b->distribution); if (res) return(res); res = strcmp(a->name, b->name); return(res); } /* * sort all the RPMs by Vendor. */ rpmDataPtr rpmVendorSort(rpmDataPtr list, int installed) { rpmDataPtr res; res = rpmGenericSort(rpmVendorCmp, list, installed); return(res); } /* * rpmDateCmp : comparison of date values, if equal, compare * distributions, then compares the names. */ int rpmDateCmp(rpmDataPtr a, rpmDataPtr b) { int res = (b->date - a->date) / (60 * 60 * 12); if (res) return(res); res = strcmp(a->name, b->name); return(res); } /* * sort all the RPMs by Date. */ rpmDataPtr rpmDateSort(rpmDataPtr list, int installed) { rpmDataPtr res; res = rpmGenericSort(rpmDateCmp, list, installed); return(res); } /* * rpmNameCmp : comparison of names. */ int rpmNameCmp(rpmDataPtr a, rpmDataPtr b) { int res = strcasecmp(a->name, b->name); return(res); } /* * sort all the RPMs by Name. */ rpmDataPtr rpmNameSort(rpmDataPtr list, int installed) { rpmDataPtr res; res = rpmGenericSort(rpmNameCmp, list, installed); rpmGenericSortSoftware(rpmNameCmp, installed); return(res); } /* * Create a subdirectory of a given directory */ rpmSubdirPtr rpmNewSubdir(rpmSubdirPtr dir, const char *name, const char *htmlpath, const char *rpmpath, const char *color) { rpmSubdirPtr res; res = (rpmSubdirPtr) malloc(sizeof(rpmSubdir)); if (res == NULL) { fprintf(stderr, "rpmNewSubdir : running out of memory !\n"); exit(1); } res->name = strdup(name); res->nb_subdirs = 0; if (color) res->color = strdup(color); else res->color = NULL; memset(res->subdirs, 0, sizeof(res->subdirs)); if (dir == NULL) { res->htmlpath = strdup(name); res->parent = NULL; } else { res->parent = dir; if (htmlpath == NULL) { if (dir->htmlpath[0] != '\0') { char buf[500]; sprintf(buf, "%s/%s", dir->htmlpath, name); res->htmlpath = strdup(buf); } else res->htmlpath = strdup(name); } else res->htmlpath = strdup(htmlpath); if (rpmpath == NULL) { if (dir->rpmpath[0] != '\0') { char buf[500]; sprintf(buf, "%s/%s", dir->rpmpath, name); res->rpmpath = strdup(buf); } else res->rpmpath = strdup(name); } else res->rpmpath = strdup(rpmpath); if (dir->nb_subdirs < MAX_SUB_DIRECTORIES) { dir->subdirs[dir->nb_subdirs++] = res; if (dir->nb_subdirs >= MAX_SUB_DIRECTORIES) { fprintf(stderr, "Increase MAX_SUB_DIRECTORIES : %d\n", dir->nb_subdirs); } } } return(res); } /* * Remove one subdirectory from it's parent. */ void rpmRemoveSubdir(rpmSubdirPtr tree) { int i; rpmSubdirPtr cur = tree->parent; if (cur == NULL) return; /* * search the child in the parent list. */ for (i = 0;i < cur->nb_subdirs;i++) if (cur->subdirs[i] == tree) break; if (i >= cur->nb_subdirs) { fprintf(stderr, "rpmRemoveSubdir : child not referenced by parent\n"); return; } /* * Decrement the parent count, and shift the end of the array. */ cur->nb_subdirs--; for (;i < cur->nb_subdirs;i++) cur->subdirs[i] = cur->subdirs[i + 1]; cur->subdirs[i] = NULL; } /* * Free a full directory tree. */ void rpmFreeSubdir(rpmSubdirPtr tree) { int i; for (i = 0;i < tree->nb_subdirs; i++) rpmFreeSubdir(tree->subdirs[i]); free(tree->name); free(tree->htmlpath); free(tree->rpmpath); if (tree->color != NULL) free(tree->color); tree->parent = NULL; free(tree); } /* * print all RPM data blocks */ void rpmDataPrintAll(void) { rpmDataPtr cur = rpmList; while (cur != NULL) { rpmDataPrint(cur); cur = cur->next; } } /* * Try to extract an E-mail address from a string. * The string is truncated to the beginning of the E-Mail. * e.g. "Joe Average " should be truncated * to "Joe Average" */ char *extractEMail(char *string) { static char buf[200]; char *start; char *end; start = strchr(string, '@'); if (start == NULL) return(NULL); end = start; do { start--; if ((!isprint(*start)) || (isblank(*start)) || (*start == '@') || (*start == '<') || (*start == '>') || (*start == '(') || (*start == ')') || (*start == '[') || (*start == ']') || (*start == ';') || (*start == ',') || (*start == ',')) { start++; break; } } while (start != string); do { end++; if ((!isprint(*end)) || (isblank(*end)) || (*end == '@') || (*end == '<') || (*end == '>') || (*end == '(') || (*end == ')') || (*end == '[') || (*end == ']') || (*end == ';') || (*end == ',') || (*end == ',')) { break; } } while (*end != '\0'); strncpy(buf, start, end - start); buf[end - start] = '\0'; return(buf); } /* * Try to extract an URL address from a string. * The string is truncated to the beginning of the URL * e.g. "Nifty Project http://www.nifty.org/project/" * to "Nifty Project" */ char *extractURL(char *string) { static char buf[500]; char *start; char *end; start = strstr(string, "http://"); if (start == NULL) start = strstr(string, "ftp://"); if (start == NULL) return(NULL); end = start; do { start--; if ((!isprint(*start)) || (isblank(*start)) || (*start == '@') || (*start == '<') || (*start == '>') || (*start == '(') || (*start == ')') || (*start == '[') || (*start == ']') || (*start == ';') || (*start == ',') || (*start == ',')) { start++; break; } } while (start != string); do { end++; if ((!isprint(*end)) || (isblank(*end)) || (*end == '@') || (*end == '<') || (*end == '>') || (*end == '(') || (*end == ')') || (*end == '[') || (*end == ']') || (*end == ';') || (*end == ',') || (*end == ',')) { break; } } while (*end != '\0'); strncpy(buf, start, end - start); buf[end - start] = '\0'; return(buf); }