502 lines
10 KiB
C++
502 lines
10 KiB
C++
// This may look like C code, but it is really -*- C++ -*-
|
|
|
|
// ------------------------------------------------------------------
|
|
// The Goldware Library
|
|
// Copyright (C) 1990-1999 Odinn Sorensen
|
|
// Copyright (C) 1999-2000 Alexander S. Aganichev
|
|
// ------------------------------------------------------------------
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Library General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2 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
|
|
// Library General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Library General Public
|
|
// License along with this program; if not, write to the Free
|
|
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
// MA 02111-1307, USA
|
|
// ------------------------------------------------------------------
|
|
// $Id$
|
|
// ------------------------------------------------------------------
|
|
// GoldED nodelist indexing.
|
|
// ------------------------------------------------------------------
|
|
|
|
#include <gcrcall.h>
|
|
#include <gfilutil.h>
|
|
#include <gmemdbg.h>
|
|
#include <gstrall.h>
|
|
#include <gftnnlge.h>
|
|
#include <stdlib.h>
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static char* make_goldnode_name(char* inp) {
|
|
|
|
if(*inp == NUL)
|
|
return inp;
|
|
|
|
char buf[100];
|
|
char* p;
|
|
char* q;
|
|
|
|
// Convert underlines to spaces
|
|
p = inp;
|
|
while(*p)
|
|
if(*(p++) == '_')
|
|
*(p-1) = ' ';
|
|
|
|
// Strip leading spaces
|
|
p = inp;
|
|
while(isspace(*p))
|
|
p++;
|
|
q = &inp[strlen(p)-1];
|
|
|
|
// Strip trailing spaces
|
|
while(isspace(*q))
|
|
*q-- = NUL;
|
|
|
|
// Search for last space or point
|
|
while(*q != ' ' and *q != '.' and q > p)
|
|
q--;
|
|
|
|
// If last char is a point, find last space instead
|
|
if(*(q+1) == 0)
|
|
while(*q != ' ' and q > p)
|
|
q--;
|
|
|
|
// Exchange last name and first name(s)
|
|
if(p != q) {
|
|
strcpy(stpcpy(buf, q+1), ", ");
|
|
*(q+(*q == '.' ? 1 : 0)) = NUL;
|
|
strcat(buf, p);
|
|
strcpy(inp, buf);
|
|
}
|
|
struplow(inp);
|
|
|
|
return inp;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_golded_nodelist_index::fetchdata() {
|
|
|
|
int currfileno = (int)((current.pos >> 24) & 0xFF);
|
|
|
|
// currfileno == 0xFF: Entry is taken from a userlist, no nodelist available
|
|
if(currfileno != lastfileno) {
|
|
if(fhx != -1)
|
|
::close(fhx);
|
|
|
|
if(currfileno != 0xff) {
|
|
fhx = ::sopen(nodelist[currfileno].filename, O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD);
|
|
lastfileno = currfileno;
|
|
} else {
|
|
fhx = -1;
|
|
lastfileno = -1;
|
|
}
|
|
}
|
|
|
|
strunrevname(data.name, current.name);
|
|
*data.status = NUL;
|
|
*data.system = NUL;
|
|
*data.location = NUL;
|
|
*data.phone = NUL;
|
|
*data.flags = NUL;
|
|
*data.baud = NUL;
|
|
|
|
if(fhx != -1) {
|
|
|
|
char buf[256];
|
|
buf[255] = NUL;
|
|
|
|
lseekset(fhx, current.pos & 0x00FFFFFFL);
|
|
read(fhx, buf, 255);
|
|
if(*buf != ';') {
|
|
|
|
/*
|
|
char* end = strchr(buf, '\r');
|
|
if(end)
|
|
*end = NUL;
|
|
*/
|
|
strtok(buf,"\r\n");
|
|
|
|
data.unpack(buf);
|
|
}
|
|
}
|
|
|
|
data.addr = current.addr;
|
|
data.addr.make_string(data.address);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_golded_nodelist_index::getnode() {
|
|
|
|
#ifdef DEBUG
|
|
printf("<%05ld> ", node);
|
|
#endif
|
|
|
|
long seekto = node - 1L;
|
|
if(not namebrowse) {
|
|
if(index32) {
|
|
lseekset(fha, seekto*(long)sizeof(dword));
|
|
dword nseekto;
|
|
read(fha, &nseekto, sizeof(dword));
|
|
seekto = nseekto;
|
|
}
|
|
else {
|
|
lseekset(fha, seekto*(long)sizeof(word));
|
|
word nseekto;
|
|
read(fha, &nseekto, sizeof(word));
|
|
seekto = nseekto;
|
|
}
|
|
}
|
|
lseekset(fhn, seekto*(long)sizeof(_GEIdx));
|
|
read(fhn, ¤t, sizeof(_GEIdx));
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int ftn_golded_nodelist_index::namecmp() const {
|
|
|
|
#ifdef DEBUG
|
|
printf("[%s] [%s] ", searchname, current.name);
|
|
#endif
|
|
|
|
const char* a = searchname;
|
|
const char* b = current.name;
|
|
int n = 1;
|
|
int d;
|
|
while(1) {
|
|
d = g_tolower(*a) - g_tolower(*b);
|
|
if((d != 0) or (*a == NUL) or (*b == NUL))
|
|
break;
|
|
a++;
|
|
b++;
|
|
n++;
|
|
}
|
|
return d != 0 ? (d > 0 ? n : -n) : 0;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int ftn_golded_nodelist_index::addrcmp() const {
|
|
|
|
#ifdef DEBUG
|
|
printf("[%d:%d/%d.%d] [%d:%d/%d.%d] ",
|
|
searchaddr.zone, searchaddr.net, searchaddr.node, searchaddr.point,
|
|
current.addr.zone, current.addr.net, current.addr.node, current.addr.point
|
|
);
|
|
#endif
|
|
|
|
return searchaddr.compare(current.addr);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_golded_nodelist_index::searchfirst() {
|
|
|
|
if(maxnode) {
|
|
|
|
long mid;
|
|
long left = 0;
|
|
long right = maxnode;
|
|
int diff = 0;
|
|
int prevdiff;
|
|
|
|
do {
|
|
mid = (left+right)/2;
|
|
node = mid + 1;
|
|
getnode();
|
|
prevdiff = diff;
|
|
diff = namebrowse ? namecmp() : addrcmp();
|
|
#ifdef DEBUG
|
|
printf("(%d)\n", diff);
|
|
#endif
|
|
if(diff < 0)
|
|
right = mid - 1;
|
|
else if(diff > 0)
|
|
left = mid + 1;
|
|
else {
|
|
exactmatch = true;
|
|
fetchdata();
|
|
return true;
|
|
}
|
|
} while(left < right);
|
|
|
|
if(left < maxnode) {
|
|
node = left + 1;
|
|
getnode();
|
|
prevdiff = diff;
|
|
diff = namebrowse ? namecmp() : addrcmp();
|
|
#ifdef DEBUG
|
|
printf("(%d)\n", diff);
|
|
#endif
|
|
if(diff == 0) {
|
|
exactmatch = true;
|
|
fetchdata();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if(absolute(prevdiff) > absolute(diff))
|
|
previous();
|
|
else {
|
|
prevdiff = diff;
|
|
if(next()) {
|
|
diff = namebrowse ? namecmp() : addrcmp();
|
|
#ifdef DEBUG
|
|
printf("(%d)\n", diff);
|
|
#endif
|
|
if(absolute(prevdiff) >= absolute(diff))
|
|
previous();
|
|
}
|
|
else
|
|
fetchdata();
|
|
}
|
|
}
|
|
|
|
exactmatch = false;
|
|
return false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_golded_nodelist_index::search() {
|
|
|
|
if(searchfirst()) {
|
|
// Search backwards until first exact match is found
|
|
while(previous()) {
|
|
if(not exactmatch) {
|
|
next();
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
ftn_golded_nodelist_index::ftn_golded_nodelist_index() {
|
|
|
|
fha = fhn = fhx = -1;
|
|
nodelist = NULL;
|
|
nodelists = 0;
|
|
lastfileno = -1;
|
|
isopen = false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
ftn_golded_nodelist_index::~ftn_golded_nodelist_index() {
|
|
|
|
if(isopen)
|
|
close();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_golded_nodelist_index::open() {
|
|
|
|
if(isopen)
|
|
close();
|
|
|
|
fha = ::sopen(AddPath(nlpath, "goldnode.gxa"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD);
|
|
if(fha == -1) {
|
|
close();
|
|
return false;
|
|
}
|
|
|
|
fhn = ::sopen(AddPath(nlpath, "goldnode.gxn"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD);
|
|
if(fhn == -1) {
|
|
close();
|
|
return false;
|
|
}
|
|
|
|
FILE* fp = fopen(AddPath(nlpath, "goldnode.gxl"), "rt");
|
|
if(fp == NULL) {
|
|
close();
|
|
return false;
|
|
}
|
|
|
|
// Read the list index
|
|
char buf[256];
|
|
nodelists = 0;
|
|
while(fgets(buf, sizeof(buf), fp)) {
|
|
nodelist = (fstamp*)throw_realloc(nodelist, (nodelists+1)*sizeof(fstamp));
|
|
char* key;
|
|
char* val=buf;
|
|
getkeyval(&key, &val);
|
|
strcpy(nodelist[nodelists].filename, key);
|
|
MapPath(nodelist[nodelists].filename);
|
|
nodelist[nodelists].stamp = atol(val);
|
|
nodelists++;
|
|
}
|
|
fclose(fp);
|
|
|
|
maxnode = filelength(fha) / sizeof(word);
|
|
if(filelength(fhn) / sizeof(_GEIdx) < (size_t)maxnode) {
|
|
maxnode = filelength(fha) / sizeof(dword);
|
|
index32 = true;
|
|
}
|
|
else
|
|
index32 = false;
|
|
|
|
isopen = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_golded_nodelist_index::close() {
|
|
|
|
throw_release(nodelist);
|
|
nodelists = 0;
|
|
|
|
lastfileno = -1;
|
|
|
|
if(fha != -1) ::close(fha); fha = -1;
|
|
if(fhn != -1) ::close(fhn); fhn = -1;
|
|
if(fhx != -1) ::close(fhx); fhx = -1;
|
|
|
|
isopen = false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_golded_nodelist_index::find(const char* lookup_name) {
|
|
|
|
namebrowse = true;
|
|
make_goldnode_name(strcpy(searchname, lookup_name));
|
|
return search();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_golded_nodelist_index::find(const ftn_addr& addr) {
|
|
|
|
namebrowse = false;
|
|
searchaddr = addr;
|
|
return search();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_golded_nodelist_index::previous() {
|
|
|
|
if(node > 1) {
|
|
node--;
|
|
getnode();
|
|
fetchdata();
|
|
compare();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_golded_nodelist_index::next() {
|
|
|
|
if(node < maxnode) {
|
|
node++;
|
|
getnode();
|
|
fetchdata();
|
|
compare();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_golded_nodelist_index::first() {
|
|
|
|
node = 1;
|
|
getnode();
|
|
fetchdata();
|
|
compare();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_golded_nodelist_index::last() {
|
|
|
|
node = maxnode;
|
|
getnode();
|
|
fetchdata();
|
|
compare();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_golded_nodelist_index::push_state() {
|
|
|
|
statenode = node;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_golded_nodelist_index::pop_state() {
|
|
|
|
node = statenode;
|
|
getnode();
|
|
fetchdata();
|
|
compare();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
const char* ftn_golded_nodelist_index::index_name() const {
|
|
|
|
#if defined(__UNIX__)
|
|
return namebrowse ? "goldnode.gxn" : "goldnode.gxa";
|
|
#else
|
|
return namebrowse ? "GOLDNODE.GXN" : "GOLDNODE.GXA";
|
|
#endif
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
const char* ftn_golded_nodelist_index::nodelist_name() const {
|
|
|
|
if(lastfileno == -1)
|
|
return index_name();
|
|
|
|
const char* ptr = strrchr(nodelist[lastfileno].filename, '\\');
|
|
return ptr ? ptr+1 : nodelist[lastfileno].filename;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|