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.
 
 
 

250 lines
7.9 KiB

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