Logo Search packages:      
Sourcecode: deborphan version File versions  Download package

pkginfo.c

/* pkginfo.c - Retrieve information about packages for deborphan.
   Copyright (C) 2000, 2001, 2002, 2003 Cris van Pelt
   Copyright (C) 2003, 2004, 2006 Peter Palfrader

   $Id: pkginfo.c 577 2006-10-05 16:33:10Z weasel $

   Distributed under the terms of the Artistic License.
*/

/* This code is not nearly as advanced as dpkg's. It assumes a
   "perfect" statusfile. If the status-file is corrupted it may
   result in deborphan giving the wrong packages, or even crashing. */

#include <stdlib.h>
#include <string.h>
#include <regex.h>

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <deborphan.h>
#include <set.h>

#ifdef USE_XALLOC
#  include <xalloc.h>
#endif

extern int options[];

static regex_t re_statusinst, re_statushold, re_namedev, re_gnugrepv,
               re_descdummy, re_desctransit, re_statusconfig;

void
init_pkg_regex()
{
    regcomp(&re_statusinst,
          "^Status:.*[^-]installed$", REG_EXTENDED | REG_FLAGS);
    regcomp(&re_statushold,
          "^Status:hold.*[^-]installed$", REG_EXTENDED | REG_FLAGS);

    if (options[FIND_CONFIG])
          regcomp(&re_statusconfig,
            "^Status:.*config\\-files$", REG_EXTENDED | REG_FLAGS);

    if (options[GUESS]) {
      char guess[128];
      guess[0] = '\0';

      if (guess_chk(GUESS_PERL))
          strcat(guess, "^lib.*-perl$|");
      if (guess_chk(GUESS_PYTHON))
          strcat(guess, "^python[[:digit:].]*-|");
      if (guess_chk(GUESS_PIKE))
          strcat(guess, "^pike[[:digit:].]*-|");
      if (guess_chk(GUESS_RUBY))
          strcat(guess, "^lib.*-ruby$|");
      if (guess_chk(GUESS_DEV))
          strcat(guess, "-dev$|");
      if (guess_chk(GUESS_DEBUG))
          strcat(guess, "-dbg$|");
      if (guess_chk(GUESS_COMMON))
          strcat(guess, "-common$|");
      if (guess_chk(GUESS_DATA))
          strcat(guess, "-(data|music)$|");
      if (guess_chk(GUESS_DOC))
          strcat(guess, "-doc$|");
      if (guess_chk(GUESS_SECTION)) {
          strcat(guess, "^lib");
          regcomp(&re_gnugrepv, "(-perl|-dev|-doc|-dbg)$", 
                REG_EXTENDED | REG_FLAGS);
      }

      /* GUESS_DUMMY is a fake. It is not handled like other guess options
       * because the package's name is not really checked, but its
       * description line. The reason we sort of pretend it's a real
       * guess option is that we can combine it with --guess-only and
       * guess-all.
       */
      if (guess_chk(GUESS_DUMMY)) {
          regcomp(&re_descdummy, "^Description:.*dummy", 
                REG_EXTENDED | REG_FLAGS);
          regcomp(&re_desctransit, "^Description:.*transition", 
                REG_EXTENDED | REG_FLAGS);
      }
      if (guess[strlen(guess)-1] == '|')
          guess[strlen(guess)-1] = '\0';

      regcomp(&re_namedev, guess, REG_EXTENDED | REG_FLAGS);
    }
}

void
free_pkg_regex()
{
    regfree(&re_statusinst);
    regfree(&re_statushold);
    regfree(&re_statusconfig);
    regfree(&re_namedev);
    regfree(&re_gnugrepv);
}

/* A similar "hack" was created by Paul Martin a while ago. It was not
 * implemented then for various reasons. This selects the function to
 * call to get the info, based on the first few characters.
 * Not as versatile as regular expressions, but it makes up for that in
 * speed.
 */
void
get_pkg_info(const char *line, pkg_info * package)
{
    const char c = upcase(line[0]);
    char t;

    if (strchr(line, ':') == 0) {
      fprintf(stderr, "Status file is probably invalid. Exiting.\n");
      exit (1);
    }

    switch (c) {
    case 'P':
      t = upcase(line[2]);
      switch (t) {
      case 'I':         /* PrIority */
          get_pkg_priority(line, package);
          break;
      case 'C':         /* PaCkage */
          get_pkg_name(line, package);
          break;
      case 'O':         /* PrOvides */
          get_pkg_provides(line, package);
          break;
      case 'E':         /* PrE-depends */
          get_pkg_deps(line, package);
          break;
      }
      break;
    case 'D':
      switch (upcase(line[2])) {
          case 'P':   /* DePends */
            get_pkg_deps(line, package);
            break;
          case 'S':   /* DeScription */
            get_pkg_dummy(line, package);
            break;
      }
      break;
    case 'E':                 /* Essential */
      get_pkg_essential(line, package);
      break;
    case 'I':
      get_pkg_installed_size(line, package);
      break;
    case 'R':                 /* ReCommends */
      if (options[NICE_MODE] && upcase(line[2]) == 'C')
          get_pkg_deps(line, package);
      break;
    case 'S':
      t = upcase(line[1]);
      switch (t) {
      case 'E':         /* SEction */
          get_pkg_section(line, package);
          break;
      case 'T':         /* STatus */
          get_pkg_status(line, package);
          break;
      case 'U':         /* SUggests */
          if (options[NICE_MODE])
            get_pkg_deps(line, package);
          break;
      }
    }
}

void
get_pkg_essential(const char *line, pkg_info *package)
{
    if (strcasecmp(line, "Essential:yes") == 0)
      package->essential = 1;
}

void
get_pkg_installed_size(const char *line, pkg_info *package)
{
    char *sz;

    if (strncasecmp(line, "Installed-Size:", 15) == 0)
      package->installed_size = strtol(line + 15, NULL, 10);
}

void
get_pkg_dummy(const char *line, pkg_info *package)
{
    if (!guess_chk(GUESS_DUMMY)) 
      return;

    if (regexec(&re_descdummy, line, 0, NULL, 0) == 0 || 
        regexec(&re_desctransit, line, 0, NULL, 0) == 0) {
      package->dummy = 1;
    }
}

void
get_pkg_deps(const char *line, pkg_info * package)
{
    char *tok, *line2, *version = NULL;
    unsigned int num_deps;
    unsigned int i, dup = 0;
    dep d;

    line2 = strchr(line, ':')+1;

    num_deps = package->deps_cnt;

    for (; (tok = strsep(&line2, ",|")); num_deps++) {
      /* Versions are up to dpkg. */
        if ((version = strchr(tok, '(')))
            *version = '\0';

      set_dep(&d, tok);
      dup = 0;
      for (i = 0; i<num_deps; i++ ) {
          if (pkgcmp(package->deps[i], d)) {
            dup = 1;
            break;
          }
      }

      if (dup)
          num_deps--;
      else {
          if (num_deps >= package->deps_max) {
            /* grow deps[] array */
            package->deps_max = package->deps_max ? package->deps_max*2 : INIT_DEPENDS_COUNT;
#ifdef DEBUG
            fprintf(stderr, "Growing deps field to %d.\n", package->deps_max);
            fflush(stderr);
#endif /* DEBUG */
            package->deps = xrealloc( package->deps, package->deps_max * sizeof(package->deps[0]) );
          }
          package->deps[num_deps] = d;
      }
    }

    package->deps_cnt = num_deps;
}

void
get_pkg_priority(const char *line, pkg_info * package)
{
    set_priority(package, strchr(line, ':')+1);
}

void
get_pkg_provides(const char *line, pkg_info * package)
{
    char *prov, *name;
    int i = 0;

    prov = strchr(line, ':') + 1;

    for (i = 0; (name = strsep(&prov, ",")) || !i; i++) {
      if (!name)
          name = prov;
      set_provides(package, name, i);
    }
    package->provides_cnt = i;
}

void
get_pkg_name(const char *line, pkg_info * package)
{
    set_dep(&(package->self), strchr(line, ':') + 1);
}

void
get_pkg_status(const char *line, pkg_info * package)
{
    if (!regexec(&re_statusinst, line, 0, NULL, 0))
      set_install(package);

    if (!options[FORCE_HOLD]) {
      if (!regexec(&re_statushold, line, 0, NULL, 0))
          set_hold(package);
    }
    if (options[FIND_CONFIG]) {
      if (!regexec(&re_statusconfig, line, 0, NULL, 0))
          set_config(package);
    }
}

/* Okay, this function does not really check the libraryness of a package,
 * but it checks wether the package should be checked (1) or not (0).
 */
unsigned int
is_library(pkg_info *package, int search_libdevel)
{
    if (options[ALL_PACKAGES])
      return 1;

    if (!package->section)
      return 0;

#ifndef IGNORE_ESSENTIAL
    if (package->essential)
      return 0;
#endif

    if (!options[GUESS_ONLY]) {
      if (strstr(package->section, "/libs") || 
          strstr(package->section, "/oldlibs") ||
          (search_libdevel && strstr(package->section, "/libdevel")))
          return 1;
    }

    if (!options[GUESS])
      return 0;

    /* See comments in init_pkg_regex(). */
    if (guess_chk(GUESS_DUMMY) && package->dummy)
      return 1;

    /* Avoid checking package name if we're only checking dummy,
     * which we get from the description line. 
     */
    if (guess_unique(GUESS_DUMMY))
      return 0;

    if (!regexec(&re_namedev, package->self.name, 0, NULL, 0)) {
      if (guess_chk(GUESS_SECTION) && !guess_chk(GUESS_ALL)) {
          if (regexec(&re_gnugrepv, package->self.name, 0, NULL, 0))
            return 1;
      } else {
          return 1;
      }
    }
    return 0;
}

void
get_pkg_section(const char *line, pkg_info * package)
{
    char *section;

    section = strchr(line, ':')+1;

    if (strchr(section, '/'))
      set_section(package, section, NULL);
    else
      set_section(package, section, "main");
}


Generated by  Doxygen 1.6.0   Back to index