+ bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
+
+ /* Normal packages are boxes
+ Pure Provides are triangles
+ Mixed are diamonds
+ rhomb are missing packages*/
+ const char *Shapes[] = {"ellipse","triangle","box","rhomb"};
+
+ /* Initialize the list of packages to show.
+ 1 = To Show
+ 2 = To Show no recurse
+ 3 = Emitted no recurse
+ 4 = Emitted
+ 0 = None */
+ enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
+ enum TheFlags {ForceNR=(1<<0)};
+ unsigned char *Show = new unsigned char[Cache->Head().PackageCount];
+ unsigned char *Flags = new unsigned char[Cache->Head().PackageCount];
+ unsigned char *ShapeMap = new unsigned char[Cache->Head().PackageCount];
+
+ // Show everything if no arguments given
+ if (CmdL.FileList[1] == 0)
+ for (unsigned long I = 0; I != Cache->Head().PackageCount; I++)
+ Show[I] = ToShow;
+ else
+ for (unsigned long I = 0; I != Cache->Head().PackageCount; I++)
+ Show[I] = None;
+ memset(Flags,0,sizeof(*Flags)*Cache->Head().PackageCount);
+
+ // Map the shapes
+ for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
+ {
+ if (Pkg->VersionList == 0)
+ {
+ // Missing
+ if (Pkg->ProvidesList == 0)
+ ShapeMap[Pkg->ID] = 0;
+ else
+ ShapeMap[Pkg->ID] = 1;
+ }
+ else
+ {
+ // Normal
+ if (Pkg->ProvidesList == 0)
+ ShapeMap[Pkg->ID] = 2;
+ else
+ ShapeMap[Pkg->ID] = 3;
+ }
+ }
+
+ // Load the list of packages from the command line into the show list
+ APT::CacheSetHelper helper(true, GlobalError::NOTICE);
+ std::list<APT::CacheSetHelper::PkgModifier> mods;
+ mods.push_back(APT::CacheSetHelper::PkgModifier(0, ",", APT::PackageSet::Modifier::POSTFIX));
+ mods.push_back(APT::CacheSetHelper::PkgModifier(1, "^", APT::PackageSet::Modifier::POSTFIX));
+ std::map<unsigned short, APT::PackageSet> pkgsets =
+ APT::PackageSet::GroupedFromCommandLine(CacheFile, CmdL.FileList + 1, mods, 0, helper);
+
+ for (APT::PackageSet::const_iterator Pkg = pkgsets[0].begin();
+ Pkg != pkgsets[0].end(); ++Pkg)
+ Show[Pkg->ID] = ToShow;
+ for (APT::PackageSet::const_iterator Pkg = pkgsets[1].begin();
+ Pkg != pkgsets[1].end(); ++Pkg)
+ {
+ Show[Pkg->ID] = ToShow;
+ Flags[Pkg->ID] |= ForceNR;
+ }
+
+ // Little header
+ cout << "graph: { title: \"packages\"" << endl <<
+ "xmax: 700 ymax: 700 x: 30 y: 30" << endl <<
+ "layout_downfactor: 8" << endl;
+
+ bool Act = true;
+ while (Act == true)
+ {
+ Act = false;
+ for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
+ {
+ // See we need to show this package
+ if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
+ continue;
+
+ //printf ("node: { title: \"%s\" label: \"%s\" }\n", Pkg.Name(), Pkg.Name());
+
+ // Colour as done
+ if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
+ {
+ // Pure Provides and missing packages have no deps!
+ if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
+ Show[Pkg->ID] = Done;
+ else
+ Show[Pkg->ID] = DoneNR;
+ }
+ else
+ Show[Pkg->ID] = Done;
+ Act = true;
+
+ // No deps to map out
+ if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
+ continue;
+
+ pkgCache::VerIterator Ver = Pkg.VersionList();
+ for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; ++D)
+ {
+ // See if anything can meet this dep
+ // Walk along the actual package providing versions
+ bool Hit = false;
+ pkgCache::PkgIterator DPkg = D.TargetPkg();
+ for (pkgCache::VerIterator I = DPkg.VersionList();
+ I.end() == false && Hit == false; ++I)
+ {
+ if (Cache->VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
+ Hit = true;
+ }
+
+ // Follow all provides
+ for (pkgCache::PrvIterator I = DPkg.ProvidesList();
+ I.end() == false && Hit == false; ++I)
+ {
+ if (Cache->VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
+ Hit = true;
+ }
+
+
+ // Only graph critical deps
+ if (D.IsCritical() == true)
+ {
+ printf ("edge: { sourcename: \"%s\" targetname: \"%s\" class: 2 ",Pkg.FullName(true).c_str(), D.TargetPkg().FullName(true).c_str() );
+
+ // Colour the node for recursion
+ if (Show[D.TargetPkg()->ID] <= DoneNR)
+ {
+ /* If a conflicts does not meet anything in the database
+ then show the relation but do not recurse */
+ if (Hit == false && D.IsNegative() == true)
+ {
+ if (Show[D.TargetPkg()->ID] == None &&
+ Show[D.TargetPkg()->ID] != ToShow)
+ Show[D.TargetPkg()->ID] = ToShowNR;
+ }
+ else
+ {
+ if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
+ Show[D.TargetPkg()->ID] = ToShowNR;
+ else
+ Show[D.TargetPkg()->ID] = ToShow;
+ }
+ }
+
+ // Edge colour
+ switch(D->Type)
+ {
+ case pkgCache::Dep::Conflicts:
+ printf("label: \"conflicts\" color: lightgreen }\n");
+ break;
+ case pkgCache::Dep::DpkgBreaks:
+ printf("label: \"breaks\" color: lightgreen }\n");
+ break;
+ case pkgCache::Dep::Obsoletes:
+ printf("label: \"obsoletes\" color: lightgreen }\n");
+ break;
+
+ case pkgCache::Dep::PreDepends:
+ printf("label: \"predepends\" color: blue }\n");
+ break;
+
+ default:
+ printf("}\n");
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Draw the box colours after the fact since we can not tell what colour
+ they should be until everything is finished drawing */
+ for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)