#!/mnt/utmp/cz/bin/cz++ -- using namespace std use stdio.h use map use vector use string use set use ctype.h use iostream use error use io use cstr use main const char *status = "/var/lib/dpkg/status" const char *archives= "/var/cache/apt/archives" const char *partial = "/var/cache/apt/archives/partial" set archives_files, partial_files FILE *status_file buffer input_line bool act = 1 Main() if args > 0 && strcmp(arg[0], "-n") == 0 act = 0 status_file = Fopen(status, "r") archives_files = list_files(archives) partial_files = list_files(partial) buffer_init(&input_line, 1024) repeat package *b = read_package() if b == NULL break map &dict = b->dict const char *version = dict["Version"].c_str() const char *colon = strchr(version, ':') if colon version = colon + 1 if cstr_ends_with(dict["Status"].c_str(), " installed") string prefix = dict["Package"] + "_" + version + "_" check_archives(prefix, archives, archives_files) check_archives(prefix, partial, partial_files) delete b buffer_free(&input_line) return 0 check_archives(string &prefix, const char *dir, set &files) const char *pre = prefix.c_str() set::const_iterator i = files.lower_bound(prefix), end = files.end() for ; i != end && cstr_begins_with(i->c_str(), pre) ; ++i string path = dir + ("/" + escape(*i)) cerr << "Del " << path << endl if act Remove(path.c_str()) struct package package() : dict(), order() {} map dict vector order package *read_package() package *b = new package() map &dict = b->dict vector &order = b->order string k, v repeat buffer_set_size(&input_line, 0) if Freadline(&input_line, status_file) != 0 if order.size() != 0 error("missing newline at end of file") return NULL if buffer_get_size(&input_line) == 0 return b char *l = input_line.start if isspace(l[0]) if k.length() k += "\n" ; k += l else error("continuing line before main line in database: %s", l) else char *colon = strchr(l, ':') if colon == NULL || (colon[1] != ' ' && colon[1] != '\0') error("bad syntax in database: %s", l) *colon = '\0' k = l v = colon[1] == ' ' ? colon + 2 : "" if dict.find(k) != dict.end() error("duplicate key in database: %s", l) dict[k] = v order.push_back(k) set list_files(const char *path) set list DIR *dir = Opendir(path) repeat dirent *e = Readdir(dir) if e == NULL break list.insert(unescape(string(e->d_name))) Closedir(dir) return list string unescape(const string &from) string to const char *f = from.c_str() repeat const char *percent = strchr(f, '%') if percent == NULL to += f break else to += string(f, percent) if percent[1] == '\0' || percent[2] == '\0' error("bad escaping") to += (char)strtol(string(percent+1, percent+3).c_str(), NULL, 16) f = percent + 3 return to string escape(const string &from) string to const char *f = from.c_str() repeat const char *colon = strchr(f, ':') if colon == NULL to += f break else to += string(f, colon) + "%3a" f = colon + 1 return to cstr cstr_begins_with(const char *s, const char *substr) repeat if *substr == '\0' return (cstr)s if *substr != *s return NULL ++s ; ++substr int cstr_ends_with(const char *s, const char *substr) size_t s_len = strlen(s) size_t substr_len = strlen(substr) if substr_len > s_len return 0 const char *expect = s + s_len - substr_len return cstr_eq(expect, substr) int cstr_eq(const char *s1, const char *s2) return strcmp(s1, s2) == 0