Merge commit 'grg' into HEAD
[oweals/opkg-lede.git] / libopkg / pkg_depends.c
1 /* pkg_depends.c - the opkg package management system
2
3    Steven M. Ayer
4    
5    Copyright (C) 2002 Compaq Computer Corporation
6
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.
11
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.
16 */
17
18 #include "includes.h"
19 #include <errno.h>
20 #include <ctype.h>
21    
22 #include "pkg.h"
23 #include "opkg_utils.h"
24 #include "pkg_hash.h"
25 #include "opkg_message.h"
26 #include "pkg_parse.h"
27 #include "hash_table.h"
28 #include "libbb/libbb.h"
29
30 static int parseDepends(compound_depend_t *compound_depend, char * depend_str);
31 static depend_t * depend_init(void);
32 static char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx);
33 static char ** merge_unresolved(char ** oldstuff, char ** newstuff);
34 static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg);
35
36 static int pkg_installed_and_constraint_satisfied(pkg_t *pkg, void *cdata)
37 {
38      depend_t *depend = (depend_t *)cdata;
39      if ((pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED) && version_constraints_satisfied(depend, pkg))
40           return 1;
41      else
42           return 0;
43 }
44
45 static int pkg_constraint_satisfied(pkg_t *pkg, void *cdata)
46 {
47      depend_t *depend = (depend_t *)cdata;
48      if (version_constraints_satisfied(depend, pkg))
49           return 1;
50      else
51           return 0;
52 }
53
54 /* returns ndependences or negative error value */ 
55 int
56 pkg_hash_fetch_unsatisfied_dependencies(pkg_t * pkg, pkg_vec_t *unsatisfied,
57                 char *** unresolved)
58 {
59      pkg_t * satisfier_entry_pkg;
60      int i, j, k;
61      int count, found;
62      char ** the_lost;
63      abstract_pkg_t * ab_pkg;
64
65      /* 
66       * this is a setup to check for redundant/cyclic dependency checks, 
67       * which are marked at the abstract_pkg level
68       */
69      if (!(ab_pkg = pkg->parent)) {
70           opkg_msg(ERROR, "Internal error, with pkg %s.\n", pkg->name);
71           *unresolved = NULL;
72           return 0;
73      }
74      if (ab_pkg->dependencies_checked) {    /* avoid duplicate or cyclic checks */
75           *unresolved = NULL;
76           return 0;
77      } else { 
78           ab_pkg->dependencies_checked = 1;  /* mark it for subsequent visits */
79      }
80      /**/
81
82      count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count;
83      if (!count){
84           *unresolved = NULL;
85           return 0;
86      }
87
88      the_lost = NULL;
89         
90      /* foreach dependency */
91      for (i = 0; i < count; i++) {
92           compound_depend_t * compound_depend = &pkg->depends[i];
93           depend_t ** possible_satisfiers = compound_depend->possibilities;;
94           found = 0;
95           satisfier_entry_pkg = NULL;
96
97           if (compound_depend->type == GREEDY_DEPEND) {
98                /* foreach possible satisfier */
99                for (j = 0; j < compound_depend->possibility_count; j++) {
100                     /* foreach provided_by, which includes the abstract_pkg itself */
101                     abstract_pkg_t *abpkg = possible_satisfiers[j]->pkg;
102                     abstract_pkg_vec_t *ab_provider_vec = abpkg->provided_by;
103                     int nposs = ab_provider_vec->len;
104                     abstract_pkg_t **ab_providers = ab_provider_vec->pkgs; 
105                     int l;
106                     for (l = 0; l < nposs; l++) {
107                          pkg_vec_t *test_vec = ab_providers[l]->pkgs;
108                          /* if no depends on this one, try the first package that Provides this one */
109                          if (!test_vec){   /* no pkg_vec hooked up to the abstract_pkg!  (need another feed?) */
110                               continue;
111                          }
112               
113                          /* cruise this possiblity's pkg_vec looking for an installed version */
114                          for (k = 0; k < test_vec->len; k++) {
115                               pkg_t *pkg_scout = test_vec->pkgs[k];
116                               /* not installed, and not already known about? */
117                               if ((pkg_scout->state_want != SW_INSTALL)
118                                   && !pkg_scout->parent->dependencies_checked
119                                   && !is_pkg_in_pkg_vec(unsatisfied, pkg_scout)) {
120                                    char ** newstuff = NULL;
121                                    int rc;
122                                    pkg_vec_t *tmp_vec = pkg_vec_alloc ();
123                                    /* check for not-already-installed dependencies */
124                                    rc = pkg_hash_fetch_unsatisfied_dependencies(pkg_scout,
125                                                                                 tmp_vec,
126                                                                                 &newstuff);
127                                    if (newstuff == NULL) {
128                                         int m;
129                                         int ok = 1;
130                                         for (m = 0; m < rc; m++) {
131                                             pkg_t *p = tmp_vec->pkgs[m];
132                                             if (p->state_want == SW_INSTALL)
133                                                 continue;
134                                             opkg_msg(DEBUG,
135                                                 "Not installing %s due"
136                                                 " to requirement for %s.\n",
137                                                 pkg_scout->name,
138                                                 p->name);
139                                             ok = 0;
140                                             break;
141                                         }
142                                         pkg_vec_free (tmp_vec);
143                                         if (ok) {
144                                             /* mark this one for installation */
145                                             opkg_msg(NOTICE,
146                                                 "Adding satisfier for greedy"
147                                                 " dependence %s.\n",
148                                                 pkg_scout->name);
149                                             pkg_vec_insert(unsatisfied, pkg_scout);
150                                         }
151                                    } else  {
152                                         opkg_msg(DEBUG,
153                                                 "Not installing %s due to "
154                                                 "broken depends.\n",
155                                                 pkg_scout->name);
156                                         free (newstuff);
157                                    }
158                               }
159                          }
160                     }
161                }
162
163                continue;
164           }
165
166           /* foreach possible satisfier, look for installed package  */
167           for (j = 0; j < compound_depend->possibility_count; j++) {
168                /* foreach provided_by, which includes the abstract_pkg itself */
169                depend_t *dependence_to_satisfy = possible_satisfiers[j];
170                abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg;
171                pkg_t *satisfying_pkg = 
172                     pkg_hash_fetch_best_installation_candidate(satisfying_apkg, 
173                                                                pkg_installed_and_constraint_satisfied, 
174                                                                dependence_to_satisfy, 1);
175                /* Being that I can't test constraing in pkg_hash, I will test it here */
176                if (satisfying_pkg != NULL) {
177                   if (!pkg_installed_and_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) {
178                       satisfying_pkg = NULL;
179                   }
180                }
181                opkg_msg(DEBUG, "satisfying_pkg=%p\n", satisfying_pkg);
182                if (satisfying_pkg != NULL) {
183                     found = 1;
184                     break;
185                }
186
187           }
188           /* if nothing installed matches, then look for uninstalled satisfier */
189           if (!found) {
190                /* foreach possible satisfier, look for installed package  */
191                for (j = 0; j < compound_depend->possibility_count; j++) {
192                     /* foreach provided_by, which includes the abstract_pkg itself */
193                     depend_t *dependence_to_satisfy = possible_satisfiers[j];
194                     abstract_pkg_t *satisfying_apkg = possible_satisfiers[j]->pkg;
195                     pkg_t *satisfying_pkg = 
196                          pkg_hash_fetch_best_installation_candidate(satisfying_apkg, 
197                                                                     pkg_constraint_satisfied, 
198                                                                     dependence_to_satisfy, 1);
199                     /* Being that I can't test constraing in pkg_hash, I will test it here too */
200                     if (satisfying_pkg != NULL) {
201                          if (!pkg_constraint_satisfied ( satisfying_pkg,dependence_to_satisfy)) {
202                             satisfying_pkg = NULL;
203                          }
204                     }
205
206                     /* user request overrides package recommendation */
207                     if (satisfying_pkg != NULL
208                         && (compound_depend->type == RECOMMEND || compound_depend->type == SUGGEST)
209                         && (satisfying_pkg->state_want == SW_DEINSTALL || satisfying_pkg->state_want == SW_PURGE)) {
210                          opkg_msg(NOTICE, "%s: ignoring recommendation for "
211                                         "%s at user request\n",
212                                         pkg->name, satisfying_pkg->name);
213                          continue;
214                     }
215
216                     opkg_msg(DEBUG, "satisfying_pkg=%p\n", satisfying_pkg);
217                     if (satisfying_pkg != NULL) {
218                          satisfier_entry_pkg = satisfying_pkg;
219                          break;
220                     }
221                }
222           }
223
224           /* we didn't find one, add something to the unsatisfied vector */
225           if (!found) {
226                if (!satisfier_entry_pkg) {
227                     /* failure to meet recommendations is not an error */
228                     if (compound_depend->type != RECOMMEND && compound_depend->type != SUGGEST)
229                          the_lost = add_unresolved_dep(pkg, the_lost, i);
230                     else
231                          opkg_msg(NOTICE,
232                                 "%s: unsatisfied recommendation for %s\n",
233                                 pkg->name,
234                                 compound_depend->possibilities[0]->pkg->name);
235                }
236                else {
237                     if (compound_depend->type == SUGGEST) {
238                          /* just mention it politely */
239                          opkg_msg(NOTICE, "package %s suggests installing %s\n",
240                                 pkg->name, satisfier_entry_pkg->name);
241                     } else {
242                          char ** newstuff = NULL;
243                          
244                          if (satisfier_entry_pkg != pkg &&
245                              !is_pkg_in_pkg_vec(unsatisfied, satisfier_entry_pkg)) {
246                               pkg_vec_insert(unsatisfied, satisfier_entry_pkg);
247                               pkg_hash_fetch_unsatisfied_dependencies(satisfier_entry_pkg,
248                                                                       unsatisfied,
249                                                                       &newstuff);
250                               the_lost = merge_unresolved(the_lost, newstuff);
251                               if (newstuff)
252                                    free(newstuff);
253                          }
254                     }
255                }
256           }
257      }
258      *unresolved = the_lost;
259
260      return unsatisfied->len;
261 }
262
263 /*checking for conflicts !in replaces 
264   If a packages conflicts with another but is also replacing it, I should not consider it a 
265   really conflicts 
266   returns 0 if conflicts <> replaces or 1 if conflicts == replaces 
267 */
268 static int
269 is_pkg_a_replaces(pkg_t *pkg_scout,pkg_t *pkg)
270 {
271     int i ;
272     int replaces_count = pkg->replaces_count;
273     abstract_pkg_t **replaces;
274
275     if (pkg->replaces_count==0)    // No replaces, it's surely a conflict
276         return 0;
277
278     replaces = pkg->replaces;
279
280     for (i = 0; i < replaces_count; i++) {
281         if (strcmp(pkg_scout->name,pkg->replaces[i]->name)==0) {      // Found
282             opkg_msg(DEBUG2, "Seems I've found a replace %s %s\n",
283                         pkg_scout->name, pkg->replaces[i]->name);
284             return 1;
285         }
286     }
287     return 0;
288
289 }
290
291
292 pkg_vec_t * pkg_hash_fetch_conflicts(pkg_t * pkg)
293 {
294     pkg_vec_t * installed_conflicts, * test_vec;
295     compound_depend_t * conflicts;
296     depend_t ** possible_satisfiers;
297     depend_t * possible_satisfier;
298     int i, j, k;
299     int count;
300     abstract_pkg_t * ab_pkg;
301     pkg_t **pkg_scouts; 
302     pkg_t *pkg_scout; 
303
304     /* 
305      * this is a setup to check for redundant/cyclic dependency checks, 
306      * which are marked at the abstract_pkg level
307      */
308     if(!(ab_pkg = pkg->parent)){
309         opkg_msg(ERROR, "Internal error: %s not in hash table\n", pkg->name);
310         return (pkg_vec_t *)NULL;
311     }
312
313     conflicts = pkg->conflicts;
314     if(!conflicts){
315         return (pkg_vec_t *)NULL;
316     }
317     installed_conflicts = pkg_vec_alloc();
318
319     count = pkg->conflicts_count;
320
321
322
323     /* foreach conflict */
324     for(i = 0; i < pkg->conflicts_count; i++){
325
326         possible_satisfiers = conflicts->possibilities;
327
328         /* foreach possible satisfier */
329         for(j = 0; j < conflicts->possibility_count; j++){
330             possible_satisfier = possible_satisfiers[j];
331             if (!possible_satisfier)
332                 opkg_msg(ERROR, "Internal error: possible_satisfier=NULL\n");
333             if (!possible_satisfier->pkg)
334                 opkg_msg(ERROR, "Internal error: possible_satisfier->pkg=NULL\n");
335             test_vec = possible_satisfier->pkg->pkgs;
336             if (test_vec) {
337                 /* pkg_vec found, it is an actual package conflict
338                  * cruise this possiblity's pkg_vec looking for an installed version */
339                 pkg_scouts = test_vec->pkgs;
340                 for(k = 0; k < test_vec->len; k++){
341                     pkg_scout = pkg_scouts[k];
342                     if (!pkg_scout) {
343                         opkg_msg(ERROR,  "Internal error: pkg_scout=NULL\n");
344                         continue; 
345                     }
346                     if ((pkg_scout->state_status == SS_INSTALLED || pkg_scout->state_want == SW_INSTALL) &&
347                        version_constraints_satisfied(possible_satisfier, pkg_scout) && !is_pkg_a_replaces(pkg_scout,pkg)){
348                         if (!is_pkg_in_pkg_vec(installed_conflicts, pkg_scout)){
349                             pkg_vec_insert(installed_conflicts, pkg_scout);
350                         }
351                     }
352                 }
353             }
354         }
355         conflicts++;
356     }
357
358     if (installed_conflicts->len)
359             return installed_conflicts;
360     pkg_vec_free(installed_conflicts);
361         return (pkg_vec_t *)NULL;
362 }
363
364 int version_constraints_satisfied(depend_t * depends, pkg_t * pkg)
365 {
366     pkg_t * temp;
367     int comparison;
368
369     if(depends->constraint == NONE)
370         return 1;
371
372     temp = pkg_new();
373
374     parse_version(temp, depends->version);
375
376     comparison = pkg_compare_versions(pkg, temp);
377
378     free (temp->version);
379     free(temp);
380
381     if((depends->constraint == EARLIER) && 
382        (comparison < 0))
383         return 1;
384     else if((depends->constraint == LATER) && 
385             (comparison > 0))
386         return 1;
387     else if(comparison == 0)
388         return 1;
389     else if((depends->constraint == LATER_EQUAL) && 
390             (comparison >= 0))
391         return 1;
392     else if((depends->constraint == EARLIER_EQUAL) && 
393             (comparison <= 0))
394         return 1;
395     
396     return 0;
397 }
398
399 int pkg_dependence_satisfiable(depend_t *depend)
400 {
401      abstract_pkg_t *apkg = depend->pkg;
402      abstract_pkg_vec_t *provider_apkgs = apkg->provided_by;
403      int n_providers = provider_apkgs->len;
404      abstract_pkg_t **apkgs = provider_apkgs->pkgs;
405      pkg_vec_t *pkg_vec;
406      int n_pkgs ; 
407      int i;
408      int j;
409
410      for (i = 0; i < n_providers; i++) {
411           abstract_pkg_t *papkg = apkgs[i];
412           pkg_vec = papkg->pkgs;
413           if (pkg_vec) {
414                n_pkgs = pkg_vec->len;
415                for (j = 0; j < n_pkgs; j++) {
416                     pkg_t *pkg = pkg_vec->pkgs[j];
417                     if (version_constraints_satisfied(depend, pkg)) {
418                          return 1;
419                     }
420                }
421           }
422      }
423      return 0;
424 }
425
426 int pkg_dependence_satisfied(depend_t *depend)
427 {
428      abstract_pkg_t *apkg = depend->pkg;
429      abstract_pkg_vec_t *provider_apkgs = apkg->provided_by;
430      int n_providers = provider_apkgs->len;
431      abstract_pkg_t **apkgs = provider_apkgs->pkgs;
432      int i;
433      int n_pkgs;
434      int j;
435
436      for (i = 0; i < n_providers; i++) {
437           abstract_pkg_t *papkg = apkgs[i];
438           pkg_vec_t *pkg_vec = papkg->pkgs;
439           if (pkg_vec) {
440                n_pkgs = pkg_vec->len;
441                for (j = 0; j < n_pkgs; j++) {
442                     pkg_t *pkg = pkg_vec->pkgs[j];
443                     if (version_constraints_satisfied(depend, pkg)) {
444                          if (pkg->state_status == SS_INSTALLED || pkg->state_status == SS_UNPACKED)
445                               return 1;
446                     }
447                }
448           }
449      }
450      return 0;
451 }
452
453 static int is_pkg_in_pkg_vec(pkg_vec_t * vec, pkg_t * pkg)
454 {
455     int i;
456     pkg_t ** pkgs = vec->pkgs;
457
458     for(i = 0; i < vec->len; i++)
459         if((strcmp(pkg->name, (*(pkgs + i))->name) == 0)
460            && (pkg_compare_versions(pkg, *(pkgs + i)) == 0)
461            && (strcmp(pkg->architecture, (*(pkgs + i))->architecture) == 0))
462             return 1;
463     return 0;
464 }
465
466 /**
467  * pkg_replaces returns 1 if pkg->replaces contains one of replacee's provides and 0
468  * otherwise.
469  */
470 int pkg_replaces(pkg_t *pkg, pkg_t *replacee)
471 {
472      abstract_pkg_t **replaces = pkg->replaces;
473      int replaces_count = pkg->replaces_count;
474      int replacee_provides_count = replacee->provides_count;
475      int i, j;
476      for (i = 0; i < replaces_count; i++) {
477           abstract_pkg_t *abstract_replacee = replaces[i];
478           for (j = 0; j < replacee_provides_count; j++) {
479                if (replacee->provides[j] == abstract_replacee)
480                     return 1;
481           }
482      }
483      return 0;
484 }
485
486
487 /**
488  * pkg_conflicts_abstract returns 1 if pkg->conflicts contains conflictee and 0
489  * otherwise.
490  */
491 int pkg_conflicts_abstract(pkg_t *pkg, abstract_pkg_t *conflictee)
492 {
493      compound_depend_t *conflicts = pkg->conflicts;
494      int conflicts_count = pkg->conflicts_count;
495      int i, j;
496      for (i = 0; i < conflicts_count; i++) {
497           int possibility_count = conflicts[i].possibility_count;
498           struct depend **possibilities = conflicts[i].possibilities;
499           for (j = 0; j < possibility_count; j++) {
500                if (possibilities[j]->pkg == conflictee) {
501                     return 1;
502                }
503           }
504      }
505      return 0;
506 }
507
508 /**
509  * pkg_conflicts returns 1 if pkg->conflicts contains one of
510  * conflictee's provides and 0 otherwise.
511  */
512 int pkg_conflicts(pkg_t *pkg, pkg_t *conflictee)
513 {
514      compound_depend_t *conflicts = pkg->conflicts;
515      int conflicts_count = pkg->conflicts_count;
516      abstract_pkg_t **conflictee_provides = conflictee->provides;
517      int conflictee_provides_count = conflictee->provides_count;
518      int i, j, k;
519      int possibility_count;
520      struct depend **possibilities;
521      abstract_pkg_t *possibility ;
522
523      for (i = 0; i < conflicts_count; i++) {
524           possibility_count = conflicts[i].possibility_count;
525           possibilities = conflicts[i].possibilities;
526           for (j = 0; j < possibility_count; j++) {
527                possibility = possibilities[j]->pkg;
528                for (k = 0; k < conflictee_provides_count; k++) {
529                     if (possibility == conflictee_provides[k]) {
530                          return 1;
531                     }
532                }
533           }
534      }
535      return 0;
536 }
537
538 static char ** merge_unresolved(char ** oldstuff, char ** newstuff)
539 {
540     int oldlen = 0, newlen = 0;
541     char ** result;
542     int i, j;
543
544     if(!newstuff)
545         return oldstuff;
546
547     while(oldstuff && oldstuff[oldlen]) oldlen++;
548     while(newstuff && newstuff[newlen]) newlen++;
549
550     result = xrealloc(oldstuff, sizeof(char *) * (oldlen + newlen + 1));
551
552     for(i = oldlen, j = 0; i < (oldlen + newlen); i++, j++)
553         *(result + i) = *(newstuff + j);
554
555     *(result + i) = NULL;
556
557     return result;
558 }
559
560 /* 
561  * a kinda kludgy way to back out depends str from two different arrays (reg'l'r 'n pre)
562  * this is null terminated, no count is carried around 
563  */
564 char ** add_unresolved_dep(pkg_t * pkg, char ** the_lost, int ref_ndx)
565 {
566     int count;
567     char ** resized;
568
569     count = 0;
570     while(the_lost && the_lost[count]) count++;
571
572     count++;  /* need one to hold the null */
573     resized = xrealloc(the_lost, sizeof(char *) * (count + 1));
574     resized[count - 1] = pkg_depend_str(pkg, ref_ndx);
575     resized[count] = NULL;
576     
577     return resized;
578 }
579
580 void buildProvides(abstract_pkg_t * ab_pkg, pkg_t * pkg)
581 {
582     int i;
583
584     /* every pkg provides itself */
585     pkg->provides_count++;
586     abstract_pkg_vec_insert(ab_pkg->provided_by, ab_pkg);
587     pkg->provides = xcalloc(pkg->provides_count, sizeof(abstract_pkg_t *));
588     pkg->provides[0] = ab_pkg;
589
590     for (i=1; i<pkg->provides_count; i++) {
591         abstract_pkg_t *provided_abpkg = ensure_abstract_pkg_by_name(
592                         pkg->provides_str[i-1]);
593         free(pkg->provides_str[i-1]);
594
595         pkg->provides[i] = provided_abpkg;
596
597         abstract_pkg_vec_insert(provided_abpkg->provided_by, ab_pkg);
598     }
599     if (pkg->provides_str)
600         free(pkg->provides_str);
601 }
602
603 void buildConflicts(pkg_t * pkg)
604 {
605     int i;
606     compound_depend_t * conflicts;
607
608     if (!pkg->conflicts_count)
609         return;
610
611     conflicts = pkg->conflicts = xcalloc(pkg->conflicts_count, sizeof(compound_depend_t));
612     for (i = 0; i < pkg->conflicts_count; i++) {
613          conflicts->type = CONFLICTS;
614          parseDepends(conflicts, pkg->conflicts_str[i]);
615          free(pkg->conflicts_str[i]);
616          conflicts++;
617     }
618     if (pkg->conflicts_str)
619         free(pkg->conflicts_str);
620 }
621
622 void buildReplaces(abstract_pkg_t * ab_pkg, pkg_t * pkg)
623 {
624      int i;
625
626      if (!pkg->replaces_count)
627           return;
628
629      pkg->replaces = xcalloc(pkg->replaces_count, sizeof(abstract_pkg_t *));
630
631      for(i = 0; i < pkg->replaces_count; i++){
632           abstract_pkg_t *old_abpkg = ensure_abstract_pkg_by_name(pkg->replaces_str[i]);
633
634           pkg->replaces[i] = old_abpkg;
635           free(pkg->replaces_str[i]);
636
637           if (!old_abpkg->replaced_by)
638                old_abpkg->replaced_by = abstract_pkg_vec_alloc();
639           /* if a package pkg both replaces and conflicts old_abpkg,
640            * then add it to the replaced_by vector so that old_abpkg
641            * will be upgraded to ab_pkg automatically */
642           if (pkg_conflicts_abstract(pkg, old_abpkg))
643                abstract_pkg_vec_insert(old_abpkg->replaced_by, ab_pkg);
644      }
645
646      if (pkg->replaces_str)
647              free(pkg->replaces_str);
648 }
649
650 void buildDepends(pkg_t * pkg)
651 {
652      unsigned int count;
653      int i;
654      compound_depend_t * depends;
655
656      if(!(count = pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count))
657           return;
658
659      depends = pkg->depends = xcalloc(count, sizeof(compound_depend_t));
660
661      for(i = 0; i < pkg->pre_depends_count; i++){
662           parseDepends(depends, pkg->pre_depends_str[i]);
663           free(pkg->pre_depends_str[i]);
664           depends->type = PREDEPEND;
665           depends++;
666      }
667      if (pkg->pre_depends_str)
668              free(pkg->pre_depends_str);
669
670      for(i = 0; i < pkg->depends_count; i++){
671           parseDepends(depends, pkg->depends_str[i]);
672           free(pkg->depends_str[i]);
673           depends++;
674      }
675      if (pkg->depends_str)
676              free(pkg->depends_str);
677
678      for(i = 0; i < pkg->recommends_count; i++){
679           parseDepends(depends, pkg->recommends_str[i]);
680           free(pkg->recommends_str[i]);
681           depends->type = RECOMMEND;
682           depends++;
683      }
684      if(pkg->recommends_str)
685           free(pkg->recommends_str);
686
687      for(i = 0; i < pkg->suggests_count; i++){
688           parseDepends(depends, pkg->suggests_str[i]);
689           free(pkg->suggests_str[i]);
690           depends->type = SUGGEST;
691           depends++;
692      }
693      if(pkg->suggests_str)
694           free(pkg->suggests_str);
695 }
696
697 const char*
698 constraint_to_str(enum version_constraint c)
699 {
700         switch (c) {
701         case NONE:
702                 return "";
703         case EARLIER:
704                 return "< ";
705         case EARLIER_EQUAL:
706                return "<= ";
707         case EQUAL:
708                return "= ";
709         case LATER_EQUAL:
710               return ">= ";
711         case LATER:
712              return "> ";
713         }
714
715         return "";
716 }
717
718 /*
719  * Returns a printable string for pkg's dependency at the specified idx. The
720  * resultant string must be passed to free() by the caller.
721  */
722 char *
723 pkg_depend_str(pkg_t *pkg, int idx)
724 {
725         int i;
726         unsigned int len;
727         char *str;
728         compound_depend_t *cdep;
729         depend_t *dep;
730
731         len = 0;
732         cdep = &pkg->depends[idx];
733
734         /* calculate string length */
735         for (i=0; i<cdep->possibility_count; i++) {
736                 dep = cdep->possibilities[i];
737
738                 if (i != 0)
739                         len += 3; /* space, pipe, space */
740
741                 len += strlen(dep->pkg->name);
742
743                 if (dep->version) {
744                         len += 2; /* space, left parenthesis */
745                         len += 3; /* constraint string (<=, >=, etc), space */
746                         len += strlen(dep->version);
747                         len += 1; /* right parenthesis */
748                 }
749         }
750
751         str = xmalloc(len + 1); /* +1 for the NULL terminator */
752         str[0] = '\0';
753
754         for (i=0; i<cdep->possibility_count; i++) {
755                 dep = cdep->possibilities[i];
756
757                 if (i != 0)
758                         strncat(str, " | ", len);
759
760                 strncat(str, dep->pkg->name, len);
761
762                 if (dep->version) {
763                         strncat(str, " (", len);
764                         strncat(str, constraint_to_str(dep->constraint), len);
765                         strncat(str, dep->version, len);
766                         strncat(str, ")", len);
767                 }
768         }
769
770         return str;
771 }
772
773 /*
774  * WARNING: This function assumes pre_depends and depends are at the
775  * start of the pkg->depends array.
776  */
777 void buildDependedUponBy(pkg_t * pkg, abstract_pkg_t * ab_pkg)
778 {
779      compound_depend_t * depends;
780      int count, othercount;
781      int i, j;
782      abstract_pkg_t * ab_depend;
783      abstract_pkg_t ** temp;
784
785      count = pkg->pre_depends_count + pkg->depends_count;
786      depends = pkg->depends;
787
788      for (i = 0; i < count; i++) {
789           for (j = 0; j < depends->possibility_count; j++){
790                ab_depend = depends->possibilities[j]->pkg;
791                if(!ab_depend->depended_upon_by)
792                     ab_depend->depended_upon_by = xcalloc(1, sizeof(abstract_pkg_t *));
793
794                temp = ab_depend->depended_upon_by;
795                othercount = 1;
796                while(*temp){
797                     temp++;
798                     othercount++;
799                }
800                *temp = ab_pkg;
801
802                ab_depend->depended_upon_by = xrealloc(ab_depend->depended_upon_by, 
803                                                                         (othercount + 1) * sizeof(abstract_pkg_t *));
804                /* the array may have moved */
805                temp = ab_depend->depended_upon_by + othercount;
806                *temp = NULL;
807           }
808           depends++;
809      }
810 }
811
812 static depend_t * depend_init(void)
813 {
814     depend_t * d = xcalloc(1, sizeof(depend_t));    
815     d->constraint = NONE;
816     d->version = NULL;
817     d->pkg = NULL;
818     
819     return d;
820 }
821
822 static int parseDepends(compound_depend_t *compound_depend, 
823                         char * depend_str)
824 {
825      char * pkg_name, buffer[2048];
826      unsigned int num_of_ors = 0;
827      int i;
828      char * src, * dest;
829      depend_t ** possibilities;
830
831      /* first count the number of ored possibilities for satisfying dependency */
832      src = depend_str;
833      while(*src)
834           if(*src++ == '|')
835                num_of_ors++;
836
837      compound_depend->type = DEPEND;
838
839      compound_depend->possibility_count = num_of_ors + 1;
840      possibilities = xcalloc((num_of_ors + 1), sizeof(depend_t *) );
841      compound_depend->possibilities = possibilities;
842
843      src = depend_str;
844      for(i = 0; i < num_of_ors + 1; i++){
845           possibilities[i] = depend_init();
846           /* gobble up just the name first */
847           dest = buffer;
848           while(*src &&
849                 !isspace(*src) &&
850                 (*src != '(') &&
851                 (*src != '*') &&
852                 (*src != '|'))
853                *dest++ = *src++;
854           *dest = '\0';
855           pkg_name = trim_xstrdup(buffer);
856         
857           /* now look at possible version info */
858         
859           /* skip to next chars */
860           if(isspace(*src))
861                while(*src && isspace(*src)) src++;
862
863           /* extract constraint and version */
864           if(*src == '('){
865                src++;
866                if(!strncmp(src, "<<", 2)){
867                     possibilities[i]->constraint = EARLIER;
868                     src += 2;
869                }
870                else if(!strncmp(src, "<=", 2)){
871                     possibilities[i]->constraint = EARLIER_EQUAL;
872                     src += 2;
873                }
874                else if(!strncmp(src, ">=", 2)){
875                     possibilities[i]->constraint = LATER_EQUAL;
876                     src += 2;
877                }
878                else if(!strncmp(src, ">>", 2)){
879                     possibilities[i]->constraint = LATER;
880                     src += 2;
881                }
882                else if(!strncmp(src, "=", 1)){
883                     possibilities[i]->constraint = EQUAL;
884                     src++;
885                }
886                /* should these be here to support deprecated designations; dpkg does */
887                else if(!strncmp(src, "<", 1)){
888                     possibilities[i]->constraint = EARLIER_EQUAL;
889                     src++;
890                }
891                else if(!strncmp(src, ">", 1)){
892                     possibilities[i]->constraint = LATER_EQUAL;
893                     src++; 
894                }
895
896                /* now we have any constraint, pass space to version string */
897                while(isspace(*src)) src++;
898
899                /* this would be the version string */
900                dest = buffer;
901                while(*src && *src != ')')
902                     *dest++ = *src++;
903                *dest = '\0';
904
905                possibilities[i]->version = trim_xstrdup(buffer);
906           }
907           /* hook up the dependency to its abstract pkg */
908           possibilities[i]->pkg = ensure_abstract_pkg_by_name(pkg_name);
909
910           free(pkg_name);
911         
912           /* now get past the ) and any possible | chars */
913           while(*src &&
914                 (isspace(*src) ||
915                  (*src == ')') ||
916                  (*src == '|')))
917                src++;
918           if (*src == '*')
919           {
920                compound_depend->type = GREEDY_DEPEND;
921                src++;
922           }
923      }
924
925      return 0;
926 }