~ubuntu-branches/ubuntu/hardy/dbacl/hardy

« back to all changes in this revision

Viewing changes to src/hypex.c

  • Committer: Bazaar Package Importer
  • Author(s): Zak B. Elep
  • Date: 2006-03-26 22:35:35 UTC
  • mto: (2.1.1 etch) (1.1.2 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060326223535-icwiulpkzesds4mq
ImportĀ upstreamĀ versionĀ 1.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * Copyright (C) 2005 Laird Breyer
 
3
 *  
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 * 
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 * 
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
 * 
 
18
 * Author:   Laird Breyer <laird@lbreyer.com>
 
19
 */
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#include "config.h"
 
23
#endif
 
24
 
 
25
#include <math.h>
 
26
#include <ctype.h>
 
27
#include <string.h>
 
28
#include <stdlib.h>
 
29
#include <sys/stat.h>
 
30
#include <fcntl.h>
 
31
 
 
32
#if defined HAVE_UNISTD_H
 
33
#include <unistd.h> 
 
34
#endif
 
35
 
 
36
#include <locale.h>
 
37
 
 
38
#if defined HAVE_LANGINFO_H
 
39
#include <langinfo.h>
 
40
#if !defined CODESET
 
41
/* on OpenBSD, CODESET doesn't seem to be defined - 
 
42
   we use 3, which should be US-ASCII, but it's not ideal... */
 
43
#define CODESET 3
 
44
#endif
 
45
#endif
 
46
 
 
47
#include "util.h" 
 
48
#include "dbacl.h" 
 
49
#include "hypex.h"
 
50
 
 
51
 
 
52
/* global variables */
 
53
 
 
54
extern hash_bit_count_t default_max_hash_bits;
 
55
extern hash_count_t default_max_tokens;
 
56
 
 
57
extern hash_bit_count_t default_max_grow_hash_bits;
 
58
extern hash_count_t default_max_grow_tokens;
 
59
 
 
60
hash_bit_count_t decimation;
 
61
 
 
62
extern options_t u_options;
 
63
extern options_t m_options;
 
64
extern char *extn;
 
65
 
 
66
extern token_order_t ngram_order; /* defaults to 1 */
 
67
 
 
68
/* for option processing */
 
69
extern char *optarg;
 
70
extern int optind, opterr, optopt;
 
71
 
 
72
extern char *textbuf;
 
73
extern charbuf_len_t textbuf_len;
 
74
 
 
75
extern char *progname;
 
76
extern char *inputfile;
 
77
extern long inputline;
 
78
 
 
79
int exit_code = 0; /* default */
 
80
int overflow_warning = 0;
 
81
 
 
82
score_t default_stepsize = 0.1;
 
83
 
 
84
extern long system_pagesize;
 
85
 
 
86
extern void *in_iobuf;
 
87
extern void *out_iobuf;
 
88
 
 
89
 
 
90
/***********************************************************
 
91
 * MISCELLANEOUS FUNCTIONS                                 *
 
92
 ***********************************************************/
 
93
 
 
94
static void usage(char **argv) {
 
95
  fprintf(stderr, 
 
96
          "\n");
 
97
  fprintf(stderr, 
 
98
          "hypex CATDUMP1 CATDUMP2...\n");
 
99
  fprintf(stderr, 
 
100
          "\n");
 
101
  fprintf(stderr, 
 
102
          "      computes the Chernoff information and related quantities for\n");
 
103
  fprintf(stderr, 
 
104
          "      a binary hypothesis test based on the category dump files CATDUMP1, CATDUMP2.\n");
 
105
  fprintf(stderr, 
 
106
          "\n");
 
107
  fprintf(stderr, 
 
108
          "hypex -V\n");
 
109
  fprintf(stderr, 
 
110
          "\n");
 
111
  fprintf(stderr, 
 
112
          "      prints program version.\n");
 
113
}
 
114
 
 
115
/***********************************************************
 
116
 * CATEGORY PAIRED HASH TABLE FUNCTIONS                    *
 
117
 ***********************************************************/
 
118
cp_item_t *find_in_category_pair(category_pair_t *cp, hash_value_t id) {
 
119
    register cp_item_t *i, *loop;
 
120
    /* start at id */
 
121
    i = loop = &cp->hash[id & (cp->max_tokens - 1)];
 
122
 
 
123
    while( FILLEDP(i) ) {
 
124
        if( EQUALP(i->id,id) ) {
 
125
            return i; /* found id */
 
126
        } else {
 
127
            i++; /* not found */
 
128
            /* wrap around */
 
129
            i = (i >= &cp->hash[cp->max_tokens]) ? cp->hash : i; 
 
130
            if( i == loop ) {
 
131
                return NULL; /* when hash table is full */
 
132
            }
 
133
        }
 
134
    }
 
135
 
 
136
    /* empty slot, so not found */
 
137
 
 
138
    return i; 
 
139
}
 
140
 
 
141
/* returns true if the hash could be grown, false otherwise.
 
142
   When the hash is grown, the old values must be redistributed. */
 
143
bool_t grow_category_pair(category_pair_t *cp) {
 
144
  hash_count_t c, new_size;
 
145
  cp_item_t *i, temp_item;
 
146
 
 
147
  if( !(u_options & (1<<U_OPTION_GROWHASH)) ) {
 
148
    return 0;
 
149
  } else {
 
150
    if( cp->max_hash_bits < default_max_grow_hash_bits ) {
 
151
 
 
152
      /* grow the memory around the hash */
 
153
      if( (i = (cp_item_t *)realloc(cp->hash, 
 
154
                       sizeof(cp_item_t) * 
 
155
                       (1<<(cp->max_hash_bits+1)))) == NULL ) {
 
156
        errormsg(E_WARNING,
 
157
                "failed to grow hash table.\n");
 
158
        return 0;
 
159
      }
 
160
      /* we need the old value of learner->max_tokens for a while yet */
 
161
      cp->max_hash_bits++;
 
162
 
 
163
      /* realloc doesn't initialize the memory */
 
164
      memset(&((cp_item_t *)i)[cp->max_tokens], 0, 
 
165
             ((1<<cp->max_hash_bits) - cp->max_tokens) * 
 
166
             sizeof(cp_item_t));
 
167
      cp->hash = i; 
 
168
      
 
169
      /* now mark every used slot */
 
170
      for(c = 0; c < cp->max_tokens; c++) {
 
171
        if( FILLEDP(&cp->hash[c]) ) {
 
172
          SETMARK(&cp->hash[c]);
 
173
        }
 
174
      }
 
175
 
 
176
      /* now relocate each marked slot and clear it */
 
177
      new_size = (1<<cp->max_hash_bits) - 1;
 
178
      for(c = 0; c < cp->max_tokens; c++) {
 
179
        while( MARKEDP(&cp->hash[c]) ) {
 
180
          /* find where it belongs */
 
181
          i = &cp->hash[cp->hash[c].id & new_size];
 
182
          while( FILLEDP(i) && !MARKEDP(i) ) {
 
183
            i++;
 
184
            i = (i > &cp->hash[new_size]) ? cp->hash : i;
 
185
          } /* guaranteed to exit since hash is larger than original */
 
186
 
 
187
          /* clear the mark - this must happen after we look for i,
 
188
           since it should be possible to find i == learner->hash[c] */
 
189
          UNSETMARK(&cp->hash[c]); 
 
190
 
 
191
          /* now refile */
 
192
          if( i != &cp->hash[c] ) {
 
193
            if( MARKEDP(i) ) {
 
194
              /* swap */
 
195
              memcpy(&temp_item, i, sizeof(cp_item_t));
 
196
              memcpy(i, &cp->hash[c], sizeof(cp_item_t));
 
197
              memcpy(&cp->hash[c], &temp_item, sizeof(cp_item_t));
 
198
            } else {
 
199
              /* copy and clear */
 
200
              memcpy(i, &cp->hash[c], sizeof(cp_item_t));
 
201
              memset(&cp->hash[c], 0, sizeof(cp_item_t));
 
202
            }
 
203
          } 
 
204
          /* now &cp->hash[c] is marked iff there was a swap */
 
205
        }
 
206
      }
 
207
      cp->max_tokens = (1<<cp->max_hash_bits);
 
208
    } else {
 
209
      u_options &= ~(1<<U_OPTION_GROWHASH); /* it's the law */
 
210
      errormsg(E_WARNING,
 
211
               "the token hash table is nearly full, slowing down.\n"); 
 
212
    }
 
213
  }
 
214
  return 1;
 
215
}
 
216
 
 
217
void init_category_pair(category_pair_t *cp) {
 
218
  cp->max_tokens = default_max_tokens;
 
219
  cp->max_hash_bits = default_max_hash_bits;
 
220
  cp->unique_token_count = 0;
 
221
 
 
222
  cp->hash = (cp_item_t *)malloc(cp->max_tokens * sizeof(cp_item_t));
 
223
  if( !cp->hash ) {
 
224
    errormsg(E_FATAL, "failed to allocate %li bytes for pair hash.\n",
 
225
             (sizeof(cp_item_t) * ((long int)cp->max_tokens)));
 
226
  }
 
227
}
 
228
 
 
229
void free_category_pair(category_pair_t *cp) {
 
230
  if( cp->hash ) {
 
231
    free(cp->hash);
 
232
    cp->hash = NULL;
 
233
  }
 
234
}
 
235
 
 
236
/***********************************************************
 
237
 * DIVERGENCE CALCULATIONS                                 *
 
238
 ***********************************************************/
 
239
void edge_divergences(category_pair_t *cp, score_t *div_01, score_t *div_10) {
 
240
  cp_item_t *i, *e;
 
241
  double sum01 = 0.0;
 
242
  double sum10 = 0.0;
 
243
 
 
244
  double safetycheck0 = 1.0;
 
245
  double safetycheck1 = 1.0;
 
246
 
 
247
  e = cp->hash + cp->max_tokens;
 
248
  for(i = cp->hash; i != e; i++) {
 
249
    if( FILLEDP(i) ) {
 
250
      sum01 += (i->lam[0] - i->lam[1]) * 
 
251
        exp(i->lam[0] + i->ref - cp->cat[0].logZ);
 
252
      sum10 += (i->lam[1] - i->lam[0]) * 
 
253
        exp(i->lam[1] + i->ref - cp->cat[1].logZ);
 
254
 
 
255
      safetycheck0 += (exp(i->lam[0]) - 1.0) * exp(i->ref);
 
256
      safetycheck1 += (exp(i->lam[1]) - 1.0) * exp(i->ref);
 
257
    }
 
258
  }
 
259
  *div_01 = cp->cat[1].logZ - cp->cat[0].logZ + sum01;
 
260
  *div_10 = cp->cat[0].logZ - cp->cat[1].logZ + sum10;
 
261
 
 
262
  if( u_options & (1<<U_OPTION_VERBOSE) ) {
 
263
    /* this is a quick check to verify that the normalizing constants are
 
264
       roughly correct. */
 
265
    fprintf(stdout, "safetycheck: %f %f should both be close to zero\n",
 
266
            log(safetycheck0) - cp->cat[0].logZ,
 
267
            log(safetycheck1) - cp->cat[1].logZ);
 
268
  }
 
269
 
 
270
  fprintf(stdout, "# D(P0|P1) = %f\tD(P1|P0) = %f\n", 
 
271
          nats2bits(*div_01), nats2bits(*div_10));
 
272
 
 
273
}
 
274
 
 
275
void calculate_divergences(category_pair_t *cp, score_t beta,
 
276
                           score_t div_Qbeta_P[2],
 
277
                           score_t *logZbeta,
 
278
                           score_t *Psibeta) {
 
279
 
 
280
  double logQbetainc;
 
281
  double Zbeta = 1.0;
 
282
  double sum0 = 0.0;
 
283
  double sum1 = 0.0;
 
284
  double sum2 = 0.0;
 
285
  cp_item_t *i, *e;
 
286
 
 
287
  e = cp->hash + cp->max_tokens;
 
288
  for(i = cp->hash; i != e; i++) {
 
289
    if( FILLEDP(i) ) {
 
290
      logQbetainc = beta * i->lam[0] + (1.0 - beta) * i->lam[1];
 
291
 
 
292
      Zbeta += (exp(logQbetainc) - 1.0) * exp(i->ref);
 
293
 
 
294
      sum0 += (logQbetainc - i->lam[0]) * exp(logQbetainc + i->ref);
 
295
      sum1 += (logQbetainc - i->lam[1]) * exp(logQbetainc + i->ref);
 
296
 
 
297
      sum2 += (i->lam[1] - i->lam[0]) * exp(logQbetainc + i->ref);
 
298
    }
 
299
  }
 
300
 
 
301
  *logZbeta = log(Zbeta);
 
302
  div_Qbeta_P[0] = sum0/Zbeta +  cp->cat[0].logZ - (*logZbeta);
 
303
  div_Qbeta_P[1] = sum1/Zbeta +  cp->cat[1].logZ - (*logZbeta);
 
304
 
 
305
  *Psibeta = sum2/Zbeta + cp->cat[0].logZ - cp->cat[1].logZ;
 
306
 
 
307
  /* the divergences can be calculated two slightly different ways,
 
308
     either by directly using the definition as above, or by using the
 
309
     expression containing Psibeta. We do both and average, which
 
310
     might hopefully make the result more accurate. */
 
311
 
 
312
  div_Qbeta_P[0] = 
 
313
    (div_Qbeta_P[0] + 
 
314
     cp->cat[0].logZ - (*logZbeta) + (1.0 - beta) * (*Psibeta))/2.0;
 
315
 
 
316
  div_Qbeta_P[1] = 
 
317
    (div_Qbeta_P[1] + 
 
318
     cp->cat[1].logZ - (*logZbeta) - beta * (*Psibeta))/2.0;
 
319
 
 
320
  fprintf(stdout, "%f %f %f %f %f %f\n", 
 
321
          beta, nats2bits(*logZbeta), nats2bits(*Psibeta), 
 
322
          nats2bits(div_Qbeta_P[0]), nats2bits(div_Qbeta_P[1]),
 
323
          nats2bits(div_Qbeta_P[1] - div_Qbeta_P[0]));
 
324
 
 
325
}
 
326
 
 
327
 
 
328
 
 
329
/***********************************************************
 
330
 * FILE MANAGEMENT FUNCTIONS                               *
 
331
 ***********************************************************/
 
332
bool_t load_category_dump(const char *filename, category_pair_t *cp, int c) {
 
333
  FILE *input;
 
334
  char buf[MAGIC_BUFSIZE];
 
335
  int extra_lines = 0;
 
336
  bool_t ok = (bool_t)1;
 
337
 
 
338
  long unsigned int id;
 
339
  weight_t lam, dig_ref;
 
340
  int count;
 
341
 
 
342
  cp_item_t *i;
 
343
  hash_count_t linecount;
 
344
 
 
345
  if( (c != 0) && (c != 1) ) {
 
346
    errormsg(E_WARNING, "too many categories.\n");
 
347
    return 0;
 
348
  }
 
349
 
 
350
  inputline = 0;
 
351
  inputfile = (char *)filename;
 
352
 
 
353
  input = fopen(filename, "rb");
 
354
  if( input ) {
 
355
    set_iobuf_mode(input);
 
356
 
 
357
    cp->cat[c].fullfilename = strdup(filename);
 
358
    ok = load_category_header(input, &(cp->cat[c]));
 
359
    if( ok ) {
 
360
      if( !fgets(buf, MAGIC_BUFSIZE, input) ||
 
361
          strncmp(buf, MAGIC_DUMP, strlen(MAGIC_DUMP)) != 0 ) {
 
362
        errormsg(E_ERROR, 
 
363
                 "%s is not a dbacl model dump! (see dbacl(1) -d switch)\n",
 
364
                 filename);
 
365
        ok = (bool_t)0;
 
366
      } else if( (cp->cat[c].max_order != 1) ) {
 
367
        /* we don't support complicated models, only uniform reference
 
368
           measures and unigram features */
 
369
        errormsg(E_ERROR, "the category %s is not supported (model too complex)\n",
 
370
                 cp->cat[c].filename);
 
371
        ok = (bool_t)0;
 
372
      } else {
 
373
        linecount = 0;
 
374
        while( ok && fill_textbuf(input, &extra_lines) ) {
 
375
          inputline++;
 
376
          /* we don't parse the full line, only the numbers */
 
377
          if( sscanf(textbuf, MAGIC_DUMPTBL_i,
 
378
                     &lam, &dig_ref, &count, &id) == 4 ) {
 
379
            linecount++;
 
380
 
 
381
            i = find_in_category_pair(cp, id);
 
382
 
 
383
            if( i && !FILLEDP(i) &&
 
384
                ((100 * cp->unique_token_count) >= 
 
385
                 (HASH_FULL * cp->max_tokens)) && grow_category_pair(cp) ) {
 
386
              i = find_in_category_pair(cp,id);
 
387
              /* new i, go through all tests again */
 
388
            }
 
389
 
 
390
            if( i ) {
 
391
              /* we cannot allow collisions, so we simply drop 
 
392
                 the weight if the slot is full */
 
393
              switch(c) {
 
394
              case 0:
 
395
                if( !FILLEDP(i) ) {
 
396
                  SET(i->id,id);
 
397
                  i->lam[c] = lam;
 
398
                  i->ref = dig_ref;
 
399
                  i->typ.cls |= 0x01;
 
400
                  if( cp->unique_token_count < K_TOKEN_COUNT_MAX )
 
401
                    { cp->unique_token_count++; } else { overflow_warning = 1; }
 
402
                }
 
403
                break;
 
404
              case 1:
 
405
                if( FILLEDP(i) ) {
 
406
                  if( fabs(dig_ref - i->ref) > 0.00001 ) {
 
407
                    errormsg(E_WARNING, 
 
408
                             "unequal reference measures! New token ignored (id=%lx).\n",
 
409
                             id);
 
410
                  } else {
 
411
                    i->lam[c] = lam;
 
412
                    i->typ.cls++;
 
413
                  }
 
414
                } else {
 
415
                  SET(i->id,id);
 
416
                  i->lam[c] = lam;
 
417
                  i->ref = dig_ref;
 
418
                  i->typ.cls |= 0x02;
 
419
                  if( cp->unique_token_count < K_TOKEN_COUNT_MAX )
 
420
                    { cp->unique_token_count++; } else { overflow_warning = 1; }
 
421
                }
 
422
              default:
 
423
                break;
 
424
              }
 
425
            } else {
 
426
              errormsg(E_ERROR, "ran out of hashes.\n");
 
427
              ok = (bool_t)0;
 
428
            }
 
429
 
 
430
          } else if( *textbuf ) {
 
431
            errormsg(E_ERROR, "unable to parse line %ld of %s\n",
 
432
                     inputline, cp->cat[c].fullfilename);
 
433
            ok = (bool_t)0;
 
434
          }
 
435
        }
 
436
        if( ok && (linecount != cp->cat[c].model_unique_token_count) ) {
 
437
          errormsg(E_ERROR, 
 
438
                   "incorrect number of features, expectig %ld, got %ld\n",
 
439
                   (long int)cp->cat[c].model_unique_token_count, inputline);
 
440
          ok = (bool_t)0;
 
441
        }
 
442
      }
 
443
    }
 
444
    fclose(input);
 
445
  } else {
 
446
    errormsg(E_ERROR, "couldn't open %s\n", filename);
 
447
  }
 
448
 
 
449
  return ok;
 
450
}
 
451
 
 
452
 
 
453
bool_t process_dump_pair(const char *d1, const char *d2, category_pair_t *cp) {
 
454
 
 
455
  score_t div01, div10;
 
456
  score_t beta;
 
457
  score_t div_Qbeta_P[2] = {0.0, 0.0};
 
458
  score_t logZbeta;
 
459
  score_t Psibeta;
 
460
  score_t chernoff_rate = 0.0;
 
461
  score_t chernoff_beta = 0.0;
 
462
 
 
463
  if( u_options & (1<<U_OPTION_VERBOSE) ) {
 
464
    fprintf(stdout, "processing (%s, %s)\n", d1, d2);
 
465
  }
 
466
 
 
467
  if( load_category_dump(d1, cp, 0) && load_category_dump(d2, cp, 1) ) {
 
468
    if( u_options & (1<<U_OPTION_VERBOSE) ) {
 
469
      fprintf(stdout, "loaded successfully (%s, %s)\n", d1, d2);
 
470
    }
 
471
 
 
472
    edge_divergences(cp, &div01, &div10);
 
473
 
 
474
    fprintf(stdout, 
 
475
            "# beta | logZ_beta | Psi_beta | D(Q_beta|P_0) | D(Q_beta|P_1) | t \n");
 
476
    for(beta = 0.0; beta < 1.0; beta += default_stepsize) {
 
477
      if( chernoff_beta <= 0.0 ) {
 
478
        /* we haven't crossed the intersection yet, this occurs
 
479
         the first time the divergence order is inverted */
 
480
        chernoff_rate = div_Qbeta_P[0] + div_Qbeta_P[1];
 
481
        calculate_divergences(cp, beta, div_Qbeta_P, &logZbeta, &Psibeta);
 
482
        if( div_Qbeta_P[0] <= div_Qbeta_P[1] ) {
 
483
          chernoff_beta = beta - default_stepsize/2;
 
484
          chernoff_rate = (chernoff_rate + div_Qbeta_P[0] + div_Qbeta_P[1])/4;
 
485
        }
 
486
      } else {
 
487
        calculate_divergences(cp, beta, div_Qbeta_P, &logZbeta, &Psibeta);
 
488
      }
 
489
    }
 
490
    calculate_divergences(cp, 1.0, div_Qbeta_P, &logZbeta, &Psibeta);
 
491
    
 
492
    fprintf(stdout,
 
493
            "# chernoff_rate %f chernoff_beta %f\n",
 
494
            nats2bits(chernoff_rate), chernoff_beta);
 
495
 
 
496
  }
 
497
  return (bool_t)0;
 
498
}
 
499
 
 
500
 
 
501
/***********************************************************
 
502
 * MAIN FUNCTIONS                                          *
 
503
 ***********************************************************/
 
504
int set_option(int op, char *optarg) {
 
505
  int c = 0;
 
506
  switch(op) {
 
507
  case 'V':
 
508
    fprintf(stdout, "hypex version %s\n", VERSION);
 
509
    fprintf(stdout, COPYBLURB, "hypex");
 
510
    exit(0);
 
511
    break;
 
512
  case 'h': /* select memory size in powers of 2 */
 
513
    default_max_hash_bits = atoi(optarg);
 
514
    if( default_max_hash_bits > MAX_HASH_BITS ) {
 
515
      errormsg(E_WARNING,
 
516
               "maximum hash size will be 2^%d\n", 
 
517
               MAX_HASH_BITS);
 
518
      default_max_hash_bits = MAX_HASH_BITS;
 
519
    }
 
520
    default_max_tokens = (1<<default_max_hash_bits);
 
521
    c++;
 
522
    break;
 
523
  case 'H': /* select memory size in powers of 2 */
 
524
    default_max_grow_hash_bits = atoi(optarg);
 
525
    if( default_max_grow_hash_bits > MAX_HASH_BITS ) {
 
526
      errormsg(E_WARNING,
 
527
               "maximum hash size will be 2^%d\n", 
 
528
               MAX_HASH_BITS);
 
529
      default_max_grow_hash_bits = MAX_HASH_BITS;
 
530
    }
 
531
    default_max_grow_tokens = (1<<default_max_grow_hash_bits);
 
532
    u_options |= (1<<U_OPTION_GROWHASH);
 
533
    c++;
 
534
    break;
 
535
  case 's': /* select stepsize */
 
536
    default_stepsize = atof(optarg);
 
537
    if( (default_stepsize <= 0.0) ||
 
538
        (default_stepsize >= 1.0) ) {
 
539
      errormsg(E_WARNING,
 
540
               "stepsize must be between 0.0 and 1.0, using 0.1\n");
 
541
      default_stepsize = 0.1;
 
542
    }
 
543
    c++;
 
544
    break;
 
545
  case 'v':
 
546
    u_options |= (1<<U_OPTION_VERBOSE);
 
547
    break;
 
548
  default:
 
549
    c--;
 
550
    break;
 
551
  }
 
552
  return c;
 
553
}
 
554
 
 
555
void sanitize_options() {
 
556
 
 
557
  /* consistency checks */
 
558
 
 
559
  /* decide if we need some options */
 
560
 
 
561
}
 
562
 
 
563
 
 
564
int main(int argc, char **argv) {
 
565
 
 
566
  signed char op;
 
567
  category_pair_t cp;
 
568
  int i, j;
 
569
 
 
570
  progname = "hypex";
 
571
  inputfile = "";
 
572
  inputline = 0;
 
573
 
 
574
  init_category_pair(&cp);
 
575
 
 
576
  /* set up internationalization */
 
577
  if( !setlocale(LC_ALL, "") ) {
 
578
    errormsg(E_WARNING,
 
579
            "could not set locale, internationalization disabled\n");
 
580
  } else {
 
581
    if( u_options & (1<<U_OPTION_VERBOSE) ) {
 
582
      errormsg(E_WARNING,
 
583
              "international locales not supported\n");
 
584
    }
 
585
  }
 
586
 
 
587
#if defined(HAVE_GETPAGESIZE)
 
588
  system_pagesize = getpagesize();
 
589
#endif
 
590
  if( system_pagesize == -1 ) { system_pagesize = BUFSIZ; }
 
591
 
 
592
  /* parse the options */
 
593
  while( (op = getopt(argc, argv, 
 
594
                      "H:h:s:Vv")) > -1 ) {
 
595
    set_option(op, optarg);
 
596
  }
 
597
 
 
598
  /* end option processing */
 
599
  sanitize_options();
 
600
 
 
601
  init_buffers();
 
602
 
 
603
  /* now process each pair of files on the command line */
 
604
  if( (optind > -1) && *(argv + optind) ) {
 
605
    for(i = optind; i < argc; i++) {
 
606
      for(j = i + 1; j < argc; j++) {
 
607
        process_dump_pair(argv[i], argv[j], &cp);
 
608
      }
 
609
    }
 
610
  } else {
 
611
    errormsg(E_ERROR, "missing model dumps! Use dbacl(1) with -d switch\n");
 
612
    usage(argv);
 
613
    exit(0);
 
614
  }
 
615
  
 
616
  free_category_pair(&cp);
 
617
 
 
618
  cleanup_buffers();
 
619
 
 
620
  return exit_code;
 
621
}
 
622
 
 
623