/* deborphan.h
   Copyright (C) 2000, 2001, 2002, 2003 Cris van Pelt
   Copyright (C) 2003, 2004 Peter Palfrader
   Copyright (C) 2008, 2009 Carsten Hey

   $Id: deborphan.h 871 2010-12-12 20:19:35Z carsten $

   Distributed under the terms of the Artistic License.
*/
#ifndef _DEBORPHAN_H
#  define _DEBORPHAN_H

#include <stdio.h>

#ifdef HAVE_CONFIG_H /* define some defaults if necessary. */
#  include <config.h>
#else
#  define USE_XALLOC 1
#  define DEFAULT_NICE 1
#  define STATUS_FILE "/var/lib/dpkg/status"
#  define REG_FLAGS REG_ICASE
#  define PACKAGE "deborphan"
#  ifndef VERSION
#    define VERSION "[unknown]"
#  endif
#  define DEBFOSTER_KEEP "/etc/apt/keepers"
#endif

#ifndef KEEPER_FILE
#  define KEEPER_FILE "/var/lib/deborphan/keep"
#endif

/* strsep, ftruncate, and fileno, are the only remaining functions that
 * are not ANSI-compliant, afaik. These #ifdef's will help compilation
 * with -ansi -pedantic -Wall, but not linking. ftruncate, and fileno
 * are not needed anymore and these #ifdefs broke splint, thus removed.
 */
#ifndef _BSD_SOURCE
extern char *strsep(char **, const char *);
#endif

#ifndef HAVE_ERRNO_H
#  define errno 0
#endif

/* Faster than toupper. Less reliable too. */
#define upcase(c) ((c) & 32 ? (c) ^ 32 : (c))

typedef struct dep {
     char *name;
     unsigned int namehash;
} dep;

/* The initial size of the provides[] and deps[] array, when
 * it is allocated for the first time.
 *
 * Should a grow be required, the count size is doubled.
 */
#define INIT_DEPENDS_COUNT 32
#define INIT_PROVIDES_COUNT 4
#define INIT_EXCLUDES_COUNT 4

/* These arrays aren't exactly neat, but it seems they suffice. */
typedef struct pkg_info {
     dep self;
     int priority;
     dep *provides;
     int provides_cnt;
     int provides_max;
     char *section;
     dep *deps;
     int deps_cnt;
     int deps_max;
     int  install;
     int  hold;
     int  essential;
     int  dummy;
     int  config;
     long installed_size;
     struct pkg_info *next;
} pkg_info;

/* Make the options[] array easier to read. */
enum { 
     SHOW_DEPS = 0, 
     NICE_MODE, 
     IGNORE_RECOMMENDS, 
     IGNORE_SUGGESTS, 
     ALL_PACKAGES, 
     PRIORITY, 
     SHOW_SECTION, 
     SHOW_PRIORITY,
     SHOW_SIZE,
     SEARCH,
     FORCE_HOLD,
     ADD_KEEP,
     DEL_KEEP,
     GUESS,
     NO_DEBFOSTER,
     GUESS_ONLY,
     LIST_KEEP,
     ZERO_KEEP,
     FIND_CONFIG,
     SEARCH_LIBDEVEL,
     CHECK_OPTIONS,
     NUM_OPTIONS /* THIS HAS TO BE THE LAST OF THIS ENUM! */
};

#define GUESS_DEV     1
#define GUESS_PERL    2
#define GUESS_SECTION 4
#define GUESS_DEBUG   8
#define GUESS_PIKE    16
#define GUESS_PYTHON  32
#define GUESS_RUBY    64
#define GUESS_DUMMY   128
#define GUESS_COMMON  256
#define GUESS_DATA    512
#define GUESS_DOC     1024
#define GUESS_MONO    2048
#define GUESS_KERNEL  4096

#define GUESS_IP      2162 /* Interpreters */
#define GUESS_ALL     8191

#define guess_chk(n) ((options[GUESS] & (n)) == (n))
#define guess_set(n) (options[GUESS] |= (n))
#define guess_clr(n) (options[GUESS] &= ~(n))
#define guess_unique(n) (!(options[GUESS] ^ (n)))
#define pkgcmp(a, b) (((a).namehash == (b).namehash ? \
                       (strcmp((a).name, (b).name) ? 0 : 1) : 0))

extern dep *keep;

/* pkginfo.c */
void init_pkg_regex();
void free_pkg_regex();
void get_pkg_info(const char *line, pkg_info *package);
void get_pkg_priority (const char *line, pkg_info *package);
void get_pkg_provides (const char *line, pkg_info *package);
void get_pkg_name (const char *line, pkg_info *package);
void get_pkg_status (const char *line, pkg_info *package);
void get_pkg_section (const char *line, pkg_info *package);
void get_pkg_deps (const char *line, pkg_info *package);
void get_pkg_essential (const char *line, pkg_info *package);
void get_pkg_installed_size(const char *line, pkg_info *package);
void get_pkg_dummy (const char *line, pkg_info *package);
unsigned int is_library(pkg_info *package, int search_libdevel);


/* libdeps.c */
void check_lib_deps(pkg_info *package, pkg_info *current_pkg);

/* exit.c */
void error(int exit_status, int error_no, const char *format, ...);
void exit_help();
void exit_improperstate();
void exit_invalid_statusfile();
void exit_version();
void print_usage();

/* string.c */
int string_to_priority(const char *priority);
const char *priority_to_string(int priority);
char *sstrsep(char **str, int c);
inline void strstripchr(char *s, int c);
inline unsigned int strhash(const char *line);

/* keep.c */
dep *readkeep(const char *kfile);
int mustkeep(dep d);
int delkeep(const char *kfile, char **del);
int addkeep(const char *kfile, char **add);
dep *mergekeep(const dep *a, const dep *b);
void listkeepall(const char *kfile);
int listkeep(const char *kfile);
char **parseargs(int argind, int argc, char **argv);
int hasduplicate(char **list);
int pkggrep(const char *sfile, char **pkgnames);


/* file.c */
#ifdef LOW_MEM
FILE *debopen(const char *file);
char *nextline(FILE **fp);
#else
char *nextline(char **s);
char *debopen(const char *file);
#endif
int zerokeep(const char *file);

/* xalloc.c */
#ifndef USE_XALLOC
#  define xmalloc malloc
#  define xcalloc calloc
#  define xrealloc realloc
#  define xmem_error
#endif /* USE_XALLOC */

#ifdef HAVE_GETOPT_LONG
#  define _get_opt(argc, argv, optstring, longopts, longindex) \
           getopt_long((argc), (argv), (optstring), (longopts), (longindex))
#else
#  define _get_opt(argc, argv, optstring, longopts, longindex) \
           getopt((argc), (argv), (optstring))
#endif

#ifdef ENABLE_NLS
#  undef _
#  define _(string) gettext(string)
#else
#  undef _
#  define _(string) (string)
#  undef setlocale
#  define setlocale(a, b)
#  undef bindtextdomain
#  define bindtextdomain(a, b)
#  undef textdomain
#  define textdomain(a)
#endif /* ENABLE_NLS */

#endif /* ! _DEBORPHAN_H */
