/*
openisis - an open implementation of the CDS/ISIS database
Version 0.8.x (patchlevel see file Version)
Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
see README for more information
EOH */
/*
$Id: openisis.c,v 1.67 2003/06/03 11:25:02 kripke Exp $
main file of openisis executable.
*/
#ifdef HAVE_PTHREAD
#define HAVE_THREADS
#endif
#include <assert.h>
#include <stdlib.h> /* free */
#include <string.h> /* strcmp */
#ifdef WIN32
# include <sys/timeb.h>
# include <sys/types.h>
# define timeval _timeb
#else
# include <unistd.h> /* gettimeofday */
#endif
#include <sys/time.h> /* gettimeofday */
#ifdef HAVE_PTHREAD
#include <pthread.h> /* threaded crashtest */
#endif
#include "openisis.h"
/*
temporary library includes for testing of functions
that should later be accessible via openisis.h
*/
#include "lio.h"
extern Db* ldb_getdb (int dbid);
/* ************************************************************
private types
*/
typedef enum { /* what to do */
DO_DUMP,
DO_SCAN, /* simple full scan */
DO_SEARCH, /* basic index based searching */
DO_TERMS, /* list terms */
DO_CHECK, /* check db */
DO_PERF, /* do random reads for performance checking */
DO_CRASH, /* do multi-threaded crashtest */
DO_SPLIT, /* split a field value */
DO_STREAM, /* stream in records */
DO_MFNLIST, /* fetch records by mfn list */
DO_IFLOAD, /* read a lk2-style file from stdin */
DO_SWLOAD, /* load stopwords */
DO_IFDUMP, /* dump a lk2-style file to stdout */
DO_FDT, /* print fdt */
DO_VUTF /* validate UTF-8 input */
} todo;
typedef enum {
FMT_MFN, /* rowid only */
FMT_MFNF, /* rowid, 1st field */
FMT_PROP, /* property style */
FMT_TXT, /* plaintext masterfile style */
FMT_TXTW /* plaintext masterfile style with W lines */
} format;
typedef enum {
IFM_DUMP,
IFM_TAB,
IFM_OLD, /* dump old index */
IFM_COPY, /* copy old index */
IFM_CHK /* check (new oxi) index */
} ifmode;
/* ************************************************************
private data
*/
static const char *pft;
static const char **term, **val;
static OpenIsisSet *post;
int nterm, nval;
static int db = -1, wdb = -1, append = 0, idxall = 0;
/* ************************************************************
private functions
*/
static int argchk ( const char *param, const char *n, const char *v )
{
return strcmp( param, n ) ? 0 : v ? 1 :
(openIsisSMsg( OPENISIS_ERR_INVAL, "no value for param '%s'", param ), 0);
} /* argchk */
static int print ( OpenIsisRec *r, int freeit, format f )
{
union { OpenIsisRec r; char buf[10000]; } x;
int i, ret;
if ( ! r ) {
if ( FMT_TXT == f )
openIsisSMsg( 1, "\n" );
return -1;
}
ret = r->rowid;
if ( pft ) {
OpenIsisRec *q;
OPENISIS_INITBUF(x);
q = openIsisFmt( &x.r, pft, r );
if ( freeit )
free( r );
freeit = q != &x.r;
r = q;
}
if ( FMT_MFN == f )
openIsisSMsg( 1, "%d\n", r->rowid );
else if ( FMT_MFNF == f )
openIsisSMsg( 1, "%d %.*s\n", r->rowid,
0 == r->len ? 1 : (int)r->field[0].len,
0 == r->len ? "-" : r->field[0].val );
else if ( FMT_TXT <= f ) {
openIsisSMsg( 1, "\n" ); /* blank line */
if ( FMT_TXTW == f )
openIsisSMsg( 1, "W\t%d\n", r->rowid );
for ( i=0; i<r->len; i++ ) {
if ( r->field[i].val )
openIsisSMsg( 1, "%d\t%.*s\n", r->field[i].tag,
(int)r->field[i].len, r->field[i].val );
else
openIsisSMsg( 1, "%d\t%d\n", r->field[i].tag, r->field[i].len );
}
} else for ( i=0; i<r->len; i++ ) {
if ( ! r->field[i].val ) { /* shouldn't happen -- numeric ? */
openIsisSMsg( 1, "%d.?=%d\n", r->rowid, r->field[i].len );
continue;
}
openIsisSMsg( 1, "%d.%d=%.*s\n", r->rowid, r->field[i].tag,
(int)r->field[i].len, r->field[i].val );
if ( r->field[i].len && '^' == *r->field[i].val ) { /* split subfields */
OpenIsisRec *rf = openIsisReadField( 0, r->field+i );
if ( rf ) {
int j;
for ( j=0; j<rf->len; j++ )
openIsisSMsg( 1, "%d.%d.%c=%.*s\n",
r->rowid, r->field[i].tag,
(0x60 & (int)rf->field[j].tag ) ?
(int)rf->field[j].tag : ' ',
(int)rf->field[j].len, rf->field[j].val );
free( rf );
}
}
}
if ( 0 <= wdb ) {
OpenIsisRec *q = 0;
int ok;
if ( append )
r->rowid = 0;
if ( idxall && r != &x.r ) { /* add index entries for all fields */
OPENISIS_INITBUF(x);
q = &x.r;
for ( i=0; i<r->len; i++ ) {
char hit[64];
OpenIsisField *fld = r->field + i;
sprintf( hit, "%d.%d.%d.1 ", r->rowid, fld->tag, i );
OPENISIS_RADDS( q, OPENISIS_XHIT, hit, q != &x.r );
OPENISIS_RCAT( q, fld->val, fld->len, q != &x.r );
}
}
ok = openIsisDWritex( wdb, r, q );
openIsisSMsg( 1, "wrote mfn %d (%d)\n", r->rowid, ok );
}
if ( freeit )
free( r );
return ret;
} /* print */
static void printid ( int id, format f )
{
if ( FMT_MFN == f && 0 > wdb )
openIsisSMsg( 1, "%d\n", id );
else
print( openIsisReadRow( db, id ), !0, f );
} /* printid */
static int printlk2 ( void *me, OpenIsisKey *key, OpenIsisHit *hit )
{
(void)me;
if ( key && hit )
/* 30 key BLANK 7 mfn BLANK 5 tag BLANK 4 occ BLANK 4 pos*/
openIsisSMsg( 1, "%-30.*s %7u %5u %4u %4u\n",
key->len, key->byt, hit->mfn, hit->tag, hit->occ, hit->pos );
return 0;
} /* printlk2 */
static int printtab ( void *me, OpenIsisKey *key, OpenIsisHit *hit )
{
(void)me;
if ( key && hit )
/* 30 key BLANK 7 mfn BLANK 5 tag BLANK 4 occ BLANK 4 pos*/
openIsisSMsg( 1, "%.*s\t%u\t%u\t%u\t%u\n",
key->len, key->byt, hit->mfn, hit->tag, hit->occ, hit->pos );
return 0;
} /* printtab */
/* timing utility. set the timeval, return milliseconds since last call. */
#ifdef WIN32
static int millis ( struct _timeb *tb )
{
struct _timeb otb = *tb;
_ftime( tb );
return (tb->time - otb.time)*1000 + (tb->millitm - otb.millitm);
} /* millis */
#else
static int millis ( struct timeval *tv )
{
struct timeval otv = *tv;
gettimeofday( tv, 0 );
return (tv->tv_sec - otv.tv_sec)*1000 + (tv->tv_usec - otv.tv_usec)/1000;
} /* millis */
#endif
#ifdef HAVE_PTHREAD
int myOpenIsisLockFunc ( int lock )
{
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; /* the "fast" kind */
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
/*
LOG_DBG( LOG_ERROR, "thread %d op 0x%08x", (int)pthread_self(), lock );
*/
switch ( OPENISIS_WAIT & lock ) {
case OPENISIS_RELE: return pthread_mutex_unlock( &mut );
case OPENISIS_LOCK: return pthread_mutex_lock( &mut );
case OPENISIS_WAKE: return pthread_cond_broadcast( &cond );
case OPENISIS_WAIT: return pthread_cond_wait( &cond, &mut );
}
return -1;
}
#else
# define myOpenIsisLockFunc 0
#endif
typedef struct {
int start;
} threadarg;
/* (p)thread routine */
static void * run ( void *arg )
{
struct timeval tv;
int m;
threadarg *my = (threadarg *)arg;
int start = my->start;
int i;
millis( &tv );
for ( i=start+1; i++!=start; ) {
int j;
if ( i >= nterm )
i = 0;
for ( j=0; j<post[i].len; j++ ) {
int mfn = post[i].id[j];
OpenIsisRec *r = openIsisReadRow( db, mfn );
if ( ! r ) {
openIsisSMsg( 2, "no rec %d\n", mfn );
continue;
}
if ( 0 >= r->len )
openIsisSMsg( 2, "no fields for %d\n", mfn );
else if ( r->field[0].len != (int)strlen(val[mfn])
|| memcmp( r->field[0].val, val[mfn], r->field[0].len )
)
openIsisSMsg( 2, "mismatch on %d\n", mfn );
free( r );
}
}
m = millis(&tv);
openIsisSMsg( 1, "thread %d@%d terminated after %.3f seconds\n",
#ifdef HAVE_THREADS
(int)pthread_self()
#else
0L
#endif
, start, m/1000. );
return (void *)m;
} /* run */
/* multithreaded crashtest */
static int crash ( const char *pre )
{
struct timeval tv;
union { OpenIsisRec r; char buf[10000]; } x;
int l;
int p = 0;
int i, pass;
int fd = 2;
threadarg def;
millis( &tv );
x.r.len = 0;
x.r.bytes = sizeof(x);
nterm = 0;
while ( openIsisTerm( &x.r, db, pre ) && x.r.len )
nterm += x.r.len;
openIsisSMsg( fd, "%d terms\n", nterm );
openIsisSMsg( fd, "%.3f sec\n", millis(&tv)/1000. );
term = (const char **)malloc( nterm * sizeof(*term) );
post = (OpenIsisSet *)malloc( nterm * sizeof(*post) );
nterm = 0;
nval = 0;
while ( openIsisTerm( &x.r, db, pre ) && x.r.len ) {
for ( i=0; i<x.r.len; i++, nterm++ ) {
int cnt;
OpenIsisSet *set = post+nterm;
char *c = malloc( x.r.field[i].len + 1 );
memcpy( c, x.r.field[i].val, x.r.field[i].len );
c[ x.r.field[i].len ] = 0;
term[ nterm ] = c;
set->len = 0;
openIsisQuery( set, db, c, OPENISIS_QRY_KEYEQ, 0 );
if ( 0 >= set->len ) {
openIsisSMsg( 2, "no results for '%s'\n", c );
return 1;
}
for ( cnt = 0; cnt < set->len; cnt++ )
if ( nval < set->id[cnt] )
nval = set->id[cnt];
p += set->len;
}
}
openIsisSMsg( fd, "%d postings max mfn %d\n", p, nval );
openIsisSMsg( fd, "%.3f sec\n", millis(&tv)/1000. );
val = (const char **)malloc( (1+nval) * sizeof(*val) );
for ( i=1; i<=nval; i++ ) {
OpenIsisRec *r = openIsisReadRow( db, i );
val[i] = 0;
if ( ! r ) {
openIsisSMsg( 2, "no rec %d\n", i );
continue;
}
if ( 0 < r->len ) {
char *c = malloc( r->field[0].len + 1 );
memcpy( c, r->field[0].val, r->field[0].len );
c[ r->field[0].len ] = 0;
val[i] = c;
}
free( r );
}
l = millis(&tv);
openIsisSMsg( fd, "sequential read %d rows in %.3f seconds %d rows per sec\n",
nval, l/1000., nval*1000/(l?l:1) );
def.start = 0;
i = 0;
run( &def );
l = millis(&tv);
run( &def );
l = millis(&tv);
run( &def );
l = millis(&tv);
openIsisSMsg( fd, "in-thread run in %.3f seconds %d rows per sec\n",
l/1000., p*1000/(l?l:1) );
#ifdef HAVE_THREADS
#define passes 3
{
static int nThreads[] = { 8, 2, 1, 4 };
int res[ sizeof(nThreads)/sizeof(nThreads[0]) ];
pthread_t th[ 8 /* max. nThreads */ ];
threadarg arg[ sizeof(th)/sizeof(th[0]) ];
int j;
for ( i=0; i<(int)(sizeof(nThreads)/sizeof(nThreads[0])); i++ )
res[i] = 0;
for ( j=0; j<(int)(sizeof(th)/sizeof(th[0])); j++ )
#if 0
if ( ! (arg[j].ses = openIsisSesGet( -1, 0 )) ) {
openIsisSMsg( fd, "could not get %dth session\n", j );
return 1;
}
#endif
for ( pass=0; pass<passes; pass++ )
for ( i=0; i<(int)(sizeof(nThreads)/sizeof(nThreads[0])); i++ ) {
int rps, avg;
millis(&tv);
assert( nThreads[i] <= (int)(sizeof(th)/sizeof(th[0])) );
for ( j=0; j<nThreads[i]; j++ ) {
arg[j].start = j*nterm/nThreads[i];
if ( pthread_create( th+j, 0, run, arg+j ) )
th[j] = (pthread_t)0;
}
openIsisSMsg( fd, "started %d threads\n", nThreads[i] );
avg = 0;
for ( j=0; j<nThreads[i]; j++ ) {
int t;
pthread_join( th[j], (void**)&t );
avg += t;
}
avg /= nThreads[i];
l = millis(&tv);
rps = (int)(nThreads[i] * p * 1000 / avg);
openIsisSMsg( fd, "joined %d threads avg %.3f after %.3f seconds %d rows per sec\n",
nThreads[i], avg/1000., l/1000., rps );
res[i] += rps;
}
for ( i=0; i<(int)(sizeof(nThreads)/sizeof(nThreads[0])); i++ )
openIsisSMsg( fd, "%d threads %d rows per sec\n", nThreads[i], res[i]/passes );
}
#else
(void)pass; /* avoid compiler warning */
#endif /* HAVE_THREADS */
return 0;
} /* crash */
/* ************************************************************
package functions
*/
/* ************************************************************
public functions
*/
int main ( int argc, const char **argv )
{
int ret = 0;
int i,intarg=0;
todo what = DO_DUMP;
format fmt = FMT_TXT;
int check = OPENISIS_CHK_FIX;
int searchmode = OPENISIS_QRY_KEYAT;
int idxmode = OPENISIS_IDXPF;
const char *search = 0;
const char *idxto = 0;
int needdb = !0;
const char *dowrite = 0;
ifmode ifm = IFM_DUMP;
OpenIsisRec *argr;
OpenIsisDb *odb;
/* initialize minimal env */
openIsisCOpen(0);
argr = openIsisRSet( 0,
OPENISIS_RFDT|OPENISIS_RARGV|OPENISIS_RIGN | (argc-1),
openIsisFdtSyspar, argv+1 );
if ( 2 == argc && ! strcmp("-version",argv[1]) ) {
openIsisSMsg( 0, "%s\n", OPENISIS_VERSION );
goto bye;
}
/* check options ... */
for ( i=0; i < argc; ) {
const char *n = argv[i], *v = 0;
assert( n );
if ( '-' == n[0] )
n++;
if ( 1 == argc - i || '-' == argv[i+1][0] ) { /* no value */
i++;
} else {
v = argv[i+1];
assert( v );
i += 2;
}
if ( argchk("logfile",n,v) )
openIsisLog( '=', v );
else if ( argchk("v",n,v) )
openIsisLog( *v, 0 );
else if ( argchk("scan",n,v) ) {
what = DO_SCAN;
search = v;
}
else if ( argchk("search",n,v) ) {
what = DO_SEARCH;
search = v;
}
else if ( argchk("upto",n,v) ) {
idxmode = OPENISIS_IDXUPTO;
idxto = v;
}
else if ( argchk("incl",n,v) ) {
idxmode = OPENISIS_IDXINCL;
idxto = v;
}
else if ( argchk("query",n,v) ) {
what = DO_SEARCH;
searchmode = OPENISIS_QRY_SIMPLE;
search = v;
}
else if ( argchk("terms",n,v) ) {
what = DO_TERMS;
search = v;
}
else if ( argchk("perf",n,v) ) {
what = DO_PERF;
intarg = atoi(v);
}
else if ( argchk("crash",n,v) ) {
what = DO_CRASH;
search = v;
}
else if ( argchk("split",n,v) ) {
what = DO_SPLIT;
search = v;
needdb = 0;
}
else if ( argchk("fmt",n,v) ) {
if ( ! strcmp("mfn",v) )
fmt =FMT_MFN;
else if ( ! strcmp("mfnf",v) )
fmt =FMT_MFNF;
else if ( ! strcmp("prop",v) )
fmt =FMT_PROP;
else if ( ! strcmp("txt",v) )
fmt =FMT_TXT;
else if ( ! strcmp("txtw",v) )
fmt =FMT_TXTW;
}
else if ( ! strcmp("check",n) )
what = DO_CHECK;
else if ( ! strcmp("vutf",n) ) {
what = DO_VUTF;
needdb = 0;
} else if ( argchk("pft",n,v) )
pft = v;
else if ( ! strcmp("stream",n) ) {
what = DO_STREAM;
needdb = 0;
} else if ( argchk("write",n,v) )
dowrite = v;
else if ( argchk("append",n,v) ) {
dowrite = v;
append = !0;
} else if ( ! strcmp("idxall",n) )
idxall = !0;
else if ( ! strcmp("mfnlist",n) )
what = DO_MFNLIST;
else if ( argchk("ifload",n,v) ) {
what = DO_IFLOAD;
intarg = atoi(v);
} else if ( ! strcmp("swload",n) ) {
what = DO_SWLOAD;
} else if ( ! strcmp("ifadd",n) ) {
what = DO_IFLOAD;
intarg = -1;
} else if ( ! strcmp("ifdel",n) ) {
what = DO_IFLOAD;
intarg = -2;
} else if ( ! strcmp("ifcopy",n) ) {
what = DO_IFDUMP;
ifm = IFM_COPY;
} else if ( ! strcmp("ifchk",n) ) {
what = DO_IFDUMP;
ifm = IFM_CHK;
} else if ( ! strcmp("iftab",n) ) {
what = DO_IFDUMP;
ifm = IFM_TAB;
} else if ( ! strcmp("ifdump",n) )
what = DO_IFDUMP;
else if ( ! strcmp("noxi",n) )
ifm = IFM_OLD;
else if ( argchk("out",n,v) ) {
char buf[256] = ">";
int l = strlen(v);
if ( l < 254 ) {
memcpy( buf+1, v, l );
buf[l+2] = 0;
openIsisSOpen( buf, 0, 0 );
}
}
else if ( argchk("fdtdump",n,v) ) {
what = DO_FDT;
intarg = atoi(v);
}
} /* while argc */
if ( needdb && 0 > (db = openIsisOpen( 0, argv + 1, argc - 1 )) ) {
openIsisSMsg( 2,
"openisis " OPENISIS_VERSION "\n\n"
"please specify a valid database with -db, e.g.\n"
"-db /winisis/data/cds\n"
"\n"
"other options are:\n"
"-search term search for term\n"
"-query \"query\" run a query like \"water * plant\"\n"
"-terms term list terms matching term (e.g. plant$)\n"
);
/* warning: string length `580' is greater than the minimum length
* `509' ISO C89 is required to support
*/
openIsisSMsg( 2,
"-fmt mfn for a search or query, list only the mfn\n"
"-fmt mfnf for a search or query, list the mfn and 1st field\n"
"-pft \"pft\" use printformat (currently very limited)\n"
"-write dbpath specify a db where records are written to\n"
"-mfnlist read mfns from stdin\n"
"-ifload pctfree read .lk2-index from stdin\n"
"\n"
"default output format is one field per line like tag<TAB>value\n"
);
ret = 1;
goto bye;
}
if ( dowrite && 0 > (wdb = openIsisOpen( dowrite, 0, 0 )) ) {
openIsisSMsg( 2, "could not open write target db '%s'\n", dowrite );
ret = 2;
goto bye;
}
switch ( what ) {
case DO_DUMP: {
int max = openIsisMaxRowid( db );
int rowid;
for ( rowid = 1; rowid <= max; rowid++ )
printid( rowid, fmt );
} break; /* DO_DUMP */
case DO_MFNLIST: {
char *buf = 0;
int l;
while ( 0 <= (l = openIsisSReadln( &buf )) ) {
int id = 0;
while ( l-- )
id = 10*id + *buf++ - '0';
if ( id )
printid( id, fmt );
}
} break; /* DO_MFNLIST */
case DO_SCAN: {
int max = openIsisMaxRowid( db );
int rowid;
for ( rowid = 1; 0 < rowid && rowid <= max; rowid++ )
rowid = print( openIsisScan( db, rowid, 0, search ), !0, fmt );
} break; /* DO_SCAN */
case DO_SEARCH: {
int cnt;
OpenIsisSet set;
set.len = 0;
openIsisQuery( &set, db, search, searchmode, 0 );
if ( 0 >= set.len ) {
openIsisSMsg( 2, "no results for '%s'\n", search );
ret = 1;
goto bye;
}
/* openIsisSMsg( 2, "%d\trows for\t%s\n", set.len, search ); */
for ( cnt = 0; cnt < set.len; cnt++ )
printid( set.id[cnt], fmt );
} break; /* DO_SEARCH */
case DO_TERMS: {
union { OpenIsisRec r; char buf[10000]; } x;
x.r.len = 0;
x.r.bytes = sizeof(x);
while ( openIsisTerm( &x.r, db, search ) && x.r.len ) {
/* openIsisSMsg( 1, "%d terms\n", x.r.len ); */
for ( i=0; i<x.r.len; i++ )
openIsisSMsg( 1, "%.*s\n", (int)x.r.field[i].len, x.r.field[i].val );
}
} break; /* DO_TERMS */
case DO_PERF: {
int max = openIsisMaxRowid( db );
while ( 0 < intarg-- ) {
OpenIsisRec *r = openIsisReadRow( db, 1+((int)rand() % max) );
free( r );
}
} break; /* DO_PERF */
case DO_CHECK:
ret = openIsisCheck( db, check );
goto bye;
case DO_CRASH:
ret = crash( search );
goto bye;
case DO_SPLIT: {
OpenIsisField f;
OpenIsisRec *r;
f.tag = 24; f.val = search; f.len = strlen(search);
r = openIsisReadField( 0, &f );
if ( r )
for ( i=0; i<r->len; i++ )
openIsisSMsg( 1, "%c=%.*s\n", (int)r->field[i].tag,
(int)r->field[i].len, r->field[i].val );
} break;
case DO_STREAM: {
OpenIsisIos ios;
OpenIsisRecStream rs = { 0, OPENISIS_STOPONEMPTY, 0, 0, 0 };
LIO_SINIT( &ios, lio_stdio, "stdin", LIO_IN );
rs.in = &ios; /* some gcc versions need it this way */
while ( 0 < (i = openIsisSGetr( &rs )) )
print( rs.rec, 0, fmt );
} break;
case DO_IFLOAD:
case DO_SWLOAD: {
OpenIsisKey key;
OpenIsisHit hit;
OpenIsisIndex idx = openIsisIdxOpen( db, intarg );
char *buf = 0;
int l, lines = 0;
memset( &hit, 0, sizeof(hit) );
hit.dbn = (-2 == intarg) ? 0xffff : 0; /* secret key for ifdel */
while ( 0 <= (l = openIsisSReadln( &buf )) && buf ) {
char *t = memchr( buf, '\t', l );
if ( DO_SWLOAD == what ) {
memcpy( key.byt, buf, key.len = (unsigned char)l );
} else if ( t ) { /* tab delimited */
key.len = (unsigned char)(t - buf);
memcpy( key.byt, buf, key.len );
if ( 0 >= (l -= t-buf+1) || !(t = memchr( buf=t+1, '\t', l )) )
continue;
hit.mfn = (unsigned) openIsisA2i( buf, t-buf );
if ( 0 >= (l -= t-buf+1) || !(t = memchr( buf=t+1, '\t', l )) )
continue;
hit.tag = (unsigned short) openIsisA2i( buf, t-buf );
if ( 0 >= (l -= t-buf+1) || !(t = memchr( buf=t+1, '\t', l )) )
continue;
hit.occ = (unsigned short) openIsisA2i( buf, t-buf );
if ( 0 >= (l -= t-buf+1) )
continue;
hit.pos = (unsigned short) openIsisA2i( t+1, l );
} else {
/* 10/30 key BLANK 7 mfn BLANK 5 tag BLANK 4 occ BLANK 4 pos*/
int eok = l - 24; /* pos of blank after key, 10 or 30 */
if ( 54 != l && 34 != l ) {
openIsisSMsg( OPENISIS_ERR_INVAL,
"bad ifload input len %d, want 34 or54 bytes + newline\n", l );
break;
}
for ( i=eok-1; ' ' == buf[i] && i--; )
;
key.len = (unsigned char) (++i);
memcpy( key.byt, buf, key.len );
log_msg( LOG_VERBOSE, "'%.*s'", 7, buf+eok+1 );
hit.mfn = (unsigned) openIsisA2i( buf+eok+1, 7 );
hit.tag = (unsigned short)openIsisA2i( buf+eok+9, 5 );
hit.occ = (unsigned short)openIsisA2i( buf+eok+15, 4 );
hit.pos = (unsigned short)openIsisA2i( buf+eok+20, 4 );
}
log_msg( LOG_VERBOSE, "'%.*s' %d %d %d %d",
key.len, key.byt, hit.mfn, hit.tag, hit.occ, hit.pos );
if ( openIsisIdxAdd( idx, &key, &hit ) )
break;
if ( !(++lines & 0x3ff) )
log_msg( LOG_INFO, "%dK lines", lines >> 10 );
}
openIsisIdxDone( idx );
} break;
case DO_IFDUMP: {
OpenIsisIdxLoop l;
memset( &l, 0, sizeof(l) );
l.flg = idxmode;
switch ( ifm ) {
case IFM_OLD:
l.flg |= OPENISIS_IDXTRAD;
case IFM_DUMP:
l.cb = (OpenIsisIdxCb*)printlk2;
break;
case IFM_TAB:
l.cb = (OpenIsisIdxCb*)printtab;
break;
case IFM_COPY:
l.flg |= OPENISIS_IDXTRAD;
l.me = openIsisIdxOpen( 0 <= wdb ? wdb : db, 0 );
l.cb = (OpenIsisIdxCb*)openIsisIdxAdd;
break;
case IFM_CHK:
/* nuttin */
break;
}
if ( search )
memcpy( l.key.byt, search,
l.key.len = (unsigned char)strlen( search ) );
if ( idxto )
memcpy( l.to.byt, idxto,
l.to.len = (unsigned char)strlen( idxto ) );
openIsisIdxLoop( db, &l );
if ( IFM_COPY == ifm )
openIsisIdxDone( (OpenIsisIndex)l.me );
} break;
case DO_FDT:
odb = ldb_getdb( db );
if ( odb && odb->fdt )
print( openIsisFFdt2Rec( odb->fdt, 0, intarg ), 0, fmt );
break;
case DO_VUTF: {
char buf[1024];
int t = 0, f = 0, g;
while ( 0 < (g = lio_read( &lio_in, buf, sizeof(buf) )) ) {
int l = openIsisValidUTF8( buf, g, &f );
if ( l ) {
openIsisSMsg( OPENISIS_ERR_INVAL,
"at total %d = %d+%d\n", l-1+t, l-1, t );
ret = 1;
goto bye;
}
t += g;
}
}
} /* switch ( what ) */
bye:
if ( 0 <= db )
openIsisClose( db );
if ( 0 <= wdb )
openIsisClose( wdb );
/* at least with WINE,
atexit cleanup is not performed
unless we explicitly call exit :(
*/
exit( ret );
return ret;
} /* openisis main */