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.
 
 
 

275 lines
8.4 KiB

  1. /* $Id: data.c,v 1.6 2000/01/07 22:45:09 joeyh 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 == postorder) {
  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. static 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. const int istask)
  95. {
  96. /* Adds package to the package list binary tree */
  97. struct package_t *node = NEW(struct package_t);
  98. void *p;
  99. char *c;
  100. char space=1;
  101. VERIFY(name != NULL);
  102. /* DPRINTF("Adding package %s to list\n", name); */
  103. memset(node, 0, sizeof(struct package_t));
  104. node->name = STRDUP(name);
  105. if (istask) {
  106. c = node->prettyname = STRDUP(name+5);
  107. /* Prettify name */
  108. while (c[0]) {
  109. if (c[0] == '-') {
  110. c[0] = ' ';
  111. space=1;
  112. }
  113. else if (space) {
  114. c[0] = toupper(c[0]);
  115. space=0;
  116. }
  117. c++;
  118. }
  119. /* Keep track of the longest name. */
  120. if (pkgs->maxnamelen < (c - node->prettyname))
  121. pkgs->maxnamelen = c - node->prettyname;
  122. }
  123. node->shortdesc = STRDUP(shortdesc);
  124. node->longdesc = STRDUP(longdesc);
  125. if (dependsdesc) node->dependscount = splitlinkdesc(dependsdesc, &node->depends);
  126. if (recommendsdesc) node->recommendscount = splitlinkdesc(recommendsdesc, &node->recommends);
  127. if (suggestsdesc) node->suggestscount = splitlinkdesc(suggestsdesc, &node->suggests);
  128. p = tsearch((void *)node, &pkgs->packages, packagecompare);
  129. VERIFY(p != NULL);
  130. pkgs->count++;
  131. }
  132. /* public functions */
  133. struct package_t *packages_find(const struct packages_t *pkgs, const char *name)
  134. {
  135. /* Given a package name, returns a pointer to the appropriate package_t structure
  136. * or NULL if none is found */
  137. struct package_t pkg;
  138. void *result;
  139. pkg.name = (char *)name;
  140. result = tfind((void *)&pkg, &pkgs->packages, packagecompare);
  141. if (result == NULL)
  142. return NULL;
  143. else
  144. return *(struct package_t **)result;
  145. }
  146. struct package_t **packages_enumerate(const struct packages_t *packages)
  147. {
  148. /* Converts the packages binary tree into a array. Do not modify the returned array! It
  149. * is a static variable managed by this module */
  150. if (_packages_enumbuf != NULL) {
  151. FREE(_packages_enumbuf);
  152. }
  153. _packages_enumbuf = MALLOC(sizeof(struct package_t *) * packages->count);
  154. if (_packages_enumbuf == NULL)
  155. DIE("Cannot allocate memory for enumeration buffer");
  156. memset(_packages_enumbuf, 0, sizeof(struct package_t *) * packages->count);
  157. _packages_enumcount = 0;
  158. twalk((void *)packages->packages, packages_walk_enumerate);
  159. ASSERT(_packages_enumcount == packages->count);
  160. return _packages_enumbuf;
  161. }
  162. void packages_readlist(struct packages_t *taskpkgs, struct packages_t *pkgs)
  163. {
  164. /* Populates internal data structures with information for an available file */
  165. FILE *f;
  166. char buf[BUF_SIZE];
  167. char *name, *shortdesc, *longdesc;
  168. char *dependsdesc, *recommendsdesc, *suggestsdesc;
  169. VERIFY(taskpkgs != NULL); VERIFY(pkgs != NULL);
  170. /* Initialization */
  171. memset(taskpkgs, 0, sizeof(struct packages_t));
  172. memset(pkgs, 0, sizeof(struct packages_t));
  173. if ((f = fopen(AVAILABLEFILE, "r")) == NULL) PERROR(AVAILABLEFILE);
  174. while (!feof(f)) {
  175. fgets(buf, BUF_SIZE, f);
  176. CHOMP(buf);
  177. if (MATCHFIELD(buf, PACKAGEFIELD)) {
  178. /*DPRINTF("Package = %s\n", FIELDDATA(buf, PACKAGEFIELD)); */
  179. name = shortdesc = longdesc = dependsdesc = recommendsdesc = suggestsdesc = NULL;
  180. name = STRDUP(FIELDDATA(buf, PACKAGEFIELD));
  181. VERIFY(name != NULL);
  182. /* look for depends/suggests and shotdesc/longdesc */
  183. while (!feof(f)) {
  184. fgets(buf, BUF_SIZE, f);
  185. CHOMP(buf);
  186. if (buf[0] == 0) break;
  187. if (MATCHFIELD(buf, DEPENDSFIELD)) {
  188. dependsdesc = STRDUP(FIELDDATA(buf, DEPENDSFIELD));
  189. VERIFY(dependsdesc != NULL);
  190. } else if (MATCHFIELD(buf, RECOMMENDSFIELD)) {
  191. recommendsdesc = STRDUP(FIELDDATA(buf, RECOMMENDSFIELD));
  192. VERIFY(recommendsdesc != NULL);
  193. } else if (MATCHFIELD(buf, SUGGESTSFIELD)) {
  194. suggestsdesc = STRDUP(FIELDDATA(buf, SUGGESTSFIELD));
  195. VERIFY(suggestsdesc != NULL);
  196. } else if (MATCHFIELD(buf, DESCRIPTIONFIELD)) {
  197. shortdesc = STRDUP(FIELDDATA(buf, DESCRIPTIONFIELD));
  198. VERIFY(shortdesc != NULL);
  199. do {
  200. fgets(buf, BUF_SIZE, f);
  201. if (buf[0] != ' ') break;
  202. if (buf[1] == '.') buf[1] = ' ';
  203. if (longdesc == NULL) {
  204. longdesc = (char *)MALLOC(strlen(buf) + 1);
  205. strcpy(longdesc, buf + 1);
  206. } else {
  207. longdesc = realloc(longdesc, strlen(longdesc) + strlen(buf) + 1);
  208. strcat(longdesc, buf + 1);
  209. }
  210. } while (buf[0] != '\n' && !feof(f));
  211. break;
  212. }
  213. }
  214. addpackage(pkgs, name, NULL, NULL, NULL, shortdesc, NULL, 0);
  215. if (strncmp(name, "task-", 5) == 0)
  216. addpackage(taskpkgs, name, dependsdesc, recommendsdesc, suggestsdesc, shortdesc, longdesc, 1);
  217. if (name != NULL) FREE(name);
  218. if (dependsdesc != NULL) FREE(dependsdesc);
  219. if (recommendsdesc != NULL) FREE(recommendsdesc);
  220. if (suggestsdesc != NULL) FREE(suggestsdesc);
  221. if (shortdesc != NULL) FREE(shortdesc);
  222. if (longdesc != NULL) FREE(longdesc);
  223. }
  224. };
  225. fclose(f);
  226. }
  227. void packages_free(struct packages_t *taskpkgs, struct packages_t *pkgs)
  228. {
  229. /* Frees up memory allocated by packages_readlist */
  230. _packages_root = taskpkgs->packages;
  231. twalk(taskpkgs->packages, packages_walk_delete);
  232. _packages_root = pkgs->packages;
  233. twalk(pkgs->packages, packages_walk_delete);
  234. if (_packages_enumbuf != NULL) FREE(_packages_enumbuf);
  235. _packages_enumbuf = NULL;
  236. }