You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

249 lines
7.8 KiB

  1. /* $Id: data.c,v 1.1 1999/11/21 22:01:04 tausq Exp $ */
  2. /* data.c - encapsulates functions for reading a package listing like dpkg's available file
  3. * Internally, packages are stored in a binary tree format to faciliate search operations
  4. */
  5. #include "data.h"
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <search.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include "util.h"
  12. #include "macros.h"
  13. #define PACKAGEFIELD "Package: "
  14. #define DEPENDSFIELD "Depends: "
  15. #define RECOMMENDSFIELD "Recommends: "
  16. #define SUGGESTSFIELD "Suggests: "
  17. #define DESCRIPTIONFIELD "Description: "
  18. #define AVAILABLEFILE "/var/lib/dpkg/available"
  19. #define BUF_SIZE 1024
  20. #define MATCHFIELD(buf, s) (strncmp(buf, s, strlen(s)) == 0)
  21. #define FIELDDATA(buf, s) (buf + strlen(s))
  22. #define CHOMP(s) if (s[strlen(s)-1] == '\n') s[strlen(s)-1] = 0
  23. /* module variables */
  24. static struct package_t **_packages_enumbuf = NULL;
  25. static int _packages_enumcount = 0;
  26. static void *_packages_root = NULL;
  27. /* private functions */
  28. static int packagecompare(const void *p1, const void *p2)
  29. {
  30. /* compares two packages by name; used for binary tree routines */
  31. char *s1, *s2;
  32. s1 = ((struct package_t *)p1)->name;
  33. s2 = ((struct package_t *)p2)->name;
  34. return strcmp(s1, s2);
  35. }
  36. static void packages_walk_enumerate(const void *nodep, const VISIT order, const int depth)
  37. {
  38. /* adds nodep to list of nodes if we haven't visited this node before */
  39. struct package_t *datap = *(struct package_t **)nodep;
  40. if (order == leaf || order == endorder) {
  41. _packages_enumcount++;
  42. _packages_enumbuf[_packages_enumcount - 1] = datap;
  43. }
  44. }
  45. static void packages_walk_delete(const void *nodep, const VISIT order, const int depth)
  46. {
  47. /* deletes memory associated with nodep */
  48. struct package_t *datap = *(struct package_t **)nodep;
  49. int i;
  50. if (order == leaf || order == endorder) {
  51. tdelete((void *)datap, &_packages_root, packagecompare);
  52. if (datap->name) FREE(datap->name);
  53. if (datap->shortdesc) FREE(datap->shortdesc);
  54. if (datap->longdesc) FREE(datap->longdesc);
  55. if (datap->depends) {
  56. for (i = 0; i < datap->dependscount; i++) FREE(datap->depends[i]);
  57. FREE(datap->depends);
  58. }
  59. if (datap->suggests) {
  60. for (i = 0; i < datap->suggestscount; i++) FREE(datap->suggests[i]);
  61. FREE(datap->suggests);
  62. }
  63. if (datap->recommends) {
  64. for (i = 0; i < datap->recommendscount; i++) FREE(datap->recommends[i]);
  65. FREE(datap->recommends);
  66. }
  67. FREE(datap);
  68. }
  69. }
  70. int splitlinkdesc(const char *desc, char ***array)
  71. {
  72. /* given a comma separate list of names, returns an array with the names split into elts of the array */
  73. char *p;
  74. char *token;
  75. int i = 0, elts = 1;
  76. VERIFY(array != NULL);
  77. *array = NULL;
  78. if (desc == NULL) return 0;
  79. p = (char *)desc;
  80. while (*p != 0) if (*p++ == ',') elts++;
  81. *array = MALLOC(sizeof(char *) * elts);
  82. memset(*array, 0, sizeof(char *) * elts);
  83. p = (char *)desc;
  84. while ((token = strsep(&p, ","))) {
  85. while (isspace(*token)) token++;
  86. (*array)[i++] = STRDUP(token);
  87. }
  88. return elts;
  89. }
  90. static void addpackage(struct packages_t *pkgs,
  91. const char *name, const char *dependsdesc, const char *recommendsdesc,
  92. const char *suggestsdesc, const char *shortdesc, const char *longdesc)
  93. {
  94. /* Adds package to the package list binary tree */
  95. struct package_t *node = NEW(struct package_t);
  96. void *p;
  97. VERIFY(name != NULL);
  98. /* DPRINTF("Adding package %s to list\n", name); */
  99. memset(node, 0, sizeof(struct package_t));
  100. node->name = STRDUP(name);
  101. node->shortdesc = STRDUP(shortdesc);
  102. node->longdesc = STRDUP(longdesc);
  103. if (dependsdesc) node->dependscount = splitlinkdesc(dependsdesc, &node->depends);
  104. if (recommendsdesc) node->recommendscount = splitlinkdesc(recommendsdesc, &node->recommends);
  105. if (suggestsdesc) node->suggestscount = splitlinkdesc(suggestsdesc, &node->suggests);
  106. p = tsearch((void *)node, &pkgs->packages, packagecompare);
  107. VERIFY(p != NULL);
  108. pkgs->count++;
  109. }
  110. /* public functions */
  111. struct package_t *packages_find(const struct packages_t *pkgs, const char *name)
  112. {
  113. /* Given a package name, returns a pointer to the appropriate package_t structure
  114. * or NULL if none is found */
  115. struct package_t pkg;
  116. void *result;
  117. pkg.name = (char *)name;
  118. result = tfind((void *)&pkg, &pkgs->packages, packagecompare);
  119. if (result == NULL)
  120. return NULL;
  121. else
  122. return *(struct package_t **)result;
  123. }
  124. struct package_t **packages_enumerate(const struct packages_t *packages)
  125. {
  126. /* Converts the packages binary tree into a array. Do not modify the returned array! It
  127. * is a static variable managed by this module */
  128. if (_packages_enumbuf != NULL) {
  129. FREE(_packages_enumbuf);
  130. }
  131. _packages_enumbuf = MALLOC(sizeof(struct package_t *) * packages->count);
  132. if (_packages_enumbuf == NULL)
  133. DIE("Cannot allocate memory for enumeration buffer");
  134. memset(_packages_enumbuf, 0, sizeof(struct package_t *) * packages->count);
  135. _packages_enumcount = 0;
  136. twalk((void *)packages->packages, packages_walk_enumerate);
  137. ASSERT(_packages_enumcount == packages->count);
  138. return _packages_enumbuf;
  139. }
  140. void packages_readlist(struct packages_t *taskpkgs, struct packages_t *pkgs)
  141. {
  142. /* Populates internal data structures with information for an available file */
  143. FILE *f;
  144. char buf[BUF_SIZE];
  145. char *name, *shortdesc, *longdesc;
  146. char *dependsdesc, *recommendsdesc, *suggestsdesc;
  147. VERIFY(taskpkgs != NULL); VERIFY(pkgs != NULL);
  148. /* Initialization */
  149. memset(taskpkgs, 0, sizeof(struct packages_t));
  150. memset(pkgs, 0, sizeof(struct packages_t));
  151. if ((f = fopen(AVAILABLEFILE, "r")) == NULL) PERROR(AVAILABLEFILE);
  152. while (!feof(f)) {
  153. fgets(buf, BUF_SIZE, f);
  154. CHOMP(buf);
  155. if (MATCHFIELD(buf, PACKAGEFIELD)) {
  156. /*DPRINTF("Package = %s\n", FIELDDATA(buf, PACKAGEFIELD)); */
  157. name = shortdesc = longdesc = dependsdesc = recommendsdesc = suggestsdesc = NULL;
  158. name = STRDUP(FIELDDATA(buf, PACKAGEFIELD));
  159. VERIFY(name != NULL);
  160. /* look for depends/suggests and shotdesc/longdesc */
  161. while (!feof(f)) {
  162. fgets(buf, BUF_SIZE, f);
  163. CHOMP(buf);
  164. if (buf[0] == 0) break;
  165. if (MATCHFIELD(buf, DEPENDSFIELD)) {
  166. dependsdesc = STRDUP(FIELDDATA(buf, DEPENDSFIELD));
  167. VERIFY(dependsdesc != NULL);
  168. } else if (MATCHFIELD(buf, RECOMMENDSFIELD)) {
  169. recommendsdesc = STRDUP(FIELDDATA(buf, RECOMMENDSFIELD));
  170. VERIFY(recommendsdesc != NULL);
  171. } else if (MATCHFIELD(buf, SUGGESTSFIELD)) {
  172. suggestsdesc = STRDUP(FIELDDATA(buf, SUGGESTSFIELD));
  173. VERIFY(suggestsdesc != NULL);
  174. } else if (MATCHFIELD(buf, DESCRIPTIONFIELD)) {
  175. shortdesc = STRDUP(FIELDDATA(buf, DESCRIPTIONFIELD));
  176. VERIFY(shortdesc != NULL);
  177. do {
  178. fgets(buf, BUF_SIZE, f);
  179. if (buf[0] != ' ') break;
  180. if (buf[1] == '.') buf[1] = ' ';
  181. if (longdesc == NULL) {
  182. longdesc = (char *)MALLOC(strlen(buf) + 1);
  183. strcpy(longdesc, buf + 1);
  184. } else {
  185. longdesc = realloc(longdesc, strlen(longdesc) + strlen(buf) + 1);
  186. strcat(longdesc, buf + 1);
  187. }
  188. } while (buf[0] != '\n' && !feof(f));
  189. break;
  190. }
  191. }
  192. addpackage(pkgs, name, NULL, NULL, NULL, shortdesc, NULL);
  193. if (strncmp(name, "task-", 5) == 0)
  194. addpackage(taskpkgs, name, dependsdesc, recommendsdesc, suggestsdesc, shortdesc, longdesc);
  195. if (name != NULL) FREE(name);
  196. if (dependsdesc != NULL) FREE(dependsdesc);
  197. if (recommendsdesc != NULL) FREE(recommendsdesc);
  198. if (suggestsdesc != NULL) FREE(suggestsdesc);
  199. if (shortdesc != NULL) FREE(shortdesc);
  200. if (longdesc != NULL) FREE(longdesc);
  201. }
  202. };
  203. fclose(f);
  204. }
  205. void packages_free(struct packages_t *taskpkgs, struct packages_t *pkgs)
  206. {
  207. /* Frees up memory allocated by packages_readlist */
  208. _packages_root = taskpkgs->packages;
  209. twalk(taskpkgs->packages, packages_walk_delete);
  210. _packages_root = pkgs->packages;
  211. twalk(pkgs->packages, packages_walk_delete);
  212. }