1649 lines
42 KiB
C++
1649 lines
42 KiB
C++
|
|
// ------------------------------------------------------------------
|
|
// The Goldware Utilities.
|
|
// Copyright (C) 1990-1999 Odinn Sorensen
|
|
// Copyright (C) 1999-2001 Alexander S. Aganichev
|
|
// Copyright (C) 2005 Stas Degteff
|
|
// ------------------------------------------------------------------
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License as
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program 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
|
|
// General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
// ------------------------------------------------------------------
|
|
// $Id$
|
|
// ------------------------------------------------------------------
|
|
// GoldNODE - A nodelist compiler for GoldED.
|
|
// ------------------------------------------------------------------
|
|
|
|
// using namespace std;
|
|
|
|
#include <gdbgerr.h>
|
|
#include <list>
|
|
#include <map>
|
|
#include <clocale>
|
|
#include <gdefs.h>
|
|
#include <gcrcall.h>
|
|
#include <gmemall.h>
|
|
#include <gfilutil.h>
|
|
#include <gftnall.h>
|
|
#include <gftnnlge.h>
|
|
#include <gstrall.h>
|
|
#include <gshare.h>
|
|
#include <gtimall.h>
|
|
#include <gutlmisc.h>
|
|
#include <gccfgg.h>
|
|
#include <gdirposx.h>
|
|
#include <gutlos.h>
|
|
#include <glog.h>
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
#define GOLDNODE_STATS 1
|
|
|
|
#ifdef GOLDNODE_STATS
|
|
#include <math.h>
|
|
#endif
|
|
|
|
#include <golded3.h>
|
|
#include <gmemdbg.h>
|
|
|
|
// ------------------------------------------------------------------
|
|
// Config versions
|
|
|
|
#define __GVER_NAME__ "GoldNode+"
|
|
#define __GVER_SHORTNAME__ "GN"
|
|
#define __gver_name__ __GVER_NAME__
|
|
#define __gver_shortname__ __GVER_SHORTNAME__
|
|
|
|
// ------------------------------------------------------------------
|
|
// 32-bit versions
|
|
|
|
const size_t maxnodes = 262000;
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
typedef std::vector<Addr>::iterator addr_iter;
|
|
typedef std::vector<Stamp>::iterator stamp_iter;
|
|
|
|
#if (_MSC_VER == 1200)
|
|
class _geidxlist : public std::list<_GEIdx>
|
|
{
|
|
public:
|
|
void sort()
|
|
{
|
|
if (2 <= size())
|
|
{
|
|
const size_t _MAXN = 15;
|
|
_Myt _X(allocator), _A[_MAXN + 1];
|
|
size_t _N = 0;
|
|
|
|
while (!empty())
|
|
{
|
|
_X.splice(_X.begin(), *this, begin());
|
|
size_t _I;
|
|
|
|
for (_I = 0; _I < _N && !_A[_I].empty(); ++_I)
|
|
{
|
|
_A[_I].merge(_X);
|
|
_A[_I].swap(_X);
|
|
}
|
|
|
|
if (_I == _MAXN) _A[_I].merge(_X);
|
|
else
|
|
{
|
|
_A[_I].swap(_X);
|
|
if (_I == _N) ++_N;
|
|
}
|
|
}
|
|
|
|
for (int _NN = _N; _NN >= 0; _NN--)
|
|
merge(_A[_NN]);
|
|
}
|
|
}
|
|
};
|
|
|
|
typedef _geidxlist geidxlist;
|
|
#else
|
|
typedef std::list<_GEIdx> geidxlist;
|
|
#endif
|
|
|
|
// Nodelists
|
|
std::vector<Stamp> nodelist; // nodelist files,stamps,update marker
|
|
std::vector<Addr> nodezone; // nodelist zones
|
|
std::vector<Stamp> userlist; // Userlist files,stamps,update marker
|
|
std::vector<Addr> userzone; // Userlist zones
|
|
std::vector< std::pair<std::string, std::string> > mappath;
|
|
|
|
// Exclude/Include nodes
|
|
std::vector<Addr> excludenode;
|
|
std::vector<Addr> includenode;
|
|
|
|
// Index files
|
|
std::string addrindex;
|
|
std::string nodeindex;
|
|
std::string listindex;
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
const word _POINT = 0x0001;
|
|
const word _NODE = 0x0002;
|
|
const word _NET = 0x0003;
|
|
const word _ZONE = 0x0004;
|
|
const word _TEST = 777;
|
|
|
|
static std::string nodepath; // Path to the nodelist files
|
|
|
|
static time32_t runtime = 0;
|
|
static int sh_mod = SH_DENYWR;
|
|
static bool fidouser = false;
|
|
static Path fidouserlst;
|
|
static bool ignoredups = false;
|
|
static size_t dups = 0;
|
|
static bool quiet = false;
|
|
|
|
#ifdef GOLDNODE_STATS
|
|
bool make_stats = false;
|
|
Path statfilename = "goldnode.stt";
|
|
|
|
struct nl_stat {
|
|
int nodename[100];
|
|
int location[100];
|
|
int sysopname[100];
|
|
};
|
|
|
|
nl_stat statistic;
|
|
#endif
|
|
|
|
char* _MapPath(char* map, bool reverse = false);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Display a "twirly"
|
|
|
|
#define TWIRLY_FACTOR 511
|
|
#define ISTWIRLY(n) (not quiet and (((n)&TWIRLY_FACTOR)==0))
|
|
|
|
static void twirly() {
|
|
|
|
static int n=0;
|
|
|
|
n = (++n)%4;
|
|
switch(n) {
|
|
case 0: std::cout << "|\b" << std::flush; break;
|
|
case 1: std::cout << "/\b" << std::flush; break;
|
|
case 2: std::cout << "-\b" << std::flush; break;
|
|
case 3: std::cout << "\\\b" << std::flush; break;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static bool match_addr_mask(Addr* mask, Addr* addr) {
|
|
|
|
if(mask->zone == GFTN_ALL or mask->zone == addr->zone)
|
|
if(mask->net == GFTN_ALL or mask->net == addr->net)
|
|
if(mask->node == GFTN_ALL or mask->node == addr->node)
|
|
if(mask->point == GFTN_ALL or mask->point == addr->point)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static bool macro_addr(char* str, int ap, Addr* addr) {
|
|
|
|
word part = 0xFFFD;
|
|
|
|
if(*str == NUL)
|
|
part = 0;
|
|
else if(isdigit(*str))
|
|
part = atow(str);
|
|
else if(*str == '?' or *str == '*')
|
|
part = GFTN_ALL;
|
|
|
|
if(ap == _TEST) {
|
|
if(part == 0xFFFD)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
switch(ap) {
|
|
case _ZONE:
|
|
addr->zone = part;
|
|
break;
|
|
case _NET:
|
|
addr->net = part;
|
|
break;
|
|
case _NODE:
|
|
addr->node = part;
|
|
break;
|
|
case _POINT:
|
|
addr->point = part;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static char* fast_parse_addr(char* str, Addr* addr) {
|
|
|
|
char* net;
|
|
char* node;
|
|
char* point;
|
|
char* domain;
|
|
char* space;
|
|
|
|
space = strchr(str, ' ');
|
|
if(space)
|
|
*space = NUL;
|
|
|
|
net = strchr(str, ':');
|
|
node = strchr(str, '/');
|
|
point = strchr(str, '.');
|
|
domain = strchr(str, '@');
|
|
if(domain and point)
|
|
if(point > domain)
|
|
point = NULL;
|
|
|
|
if(space)
|
|
*space = ' ';
|
|
|
|
if(net) {
|
|
addr->zone = atow(str);
|
|
addr->net = atow(net+1);
|
|
if(node)
|
|
addr->node = atow(node+1);
|
|
}
|
|
else {
|
|
if(node) {
|
|
if(*str != '/')
|
|
addr->net = atow(str);
|
|
addr->node = atow(node+1);
|
|
}
|
|
else {
|
|
if(point != str)
|
|
addr->node = atow(str);
|
|
}
|
|
}
|
|
if(point)
|
|
addr->point = atow(point+1);
|
|
|
|
return domain;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static char* parse_address(char* str, Addr* addr, Addr* mainaka) {
|
|
|
|
char* domain = NULL;
|
|
|
|
str = strskip_wht(str);
|
|
|
|
if(isdigit(*str) or *str == '.' or macro_addr(str, _TEST, addr)) {
|
|
|
|
char* net = strchr(str, ':');
|
|
char* node = strchr(str, '/');
|
|
char* point = strchr(str, '.');
|
|
domain = strchr(str, '@');
|
|
if(domain and point)
|
|
if(point > domain)
|
|
point = NULL;
|
|
|
|
if(net) {
|
|
macro_addr(str, _ZONE, addr);
|
|
macro_addr(net+1, _NET, addr);
|
|
if(node)
|
|
macro_addr(node+1, _NODE, addr); // zone:net/node
|
|
else
|
|
addr->node = mainaka->node; // zone:net
|
|
}
|
|
else {
|
|
addr->zone = mainaka->zone;
|
|
if(node) {
|
|
if(*str != '/')
|
|
macro_addr(str, _NET, addr); // net/node
|
|
else
|
|
addr->net = mainaka->net; // /node
|
|
macro_addr(node+1, _NODE, addr);
|
|
}
|
|
else {
|
|
if(point == str)
|
|
addr->node = mainaka->node; // .point
|
|
else
|
|
macro_addr(str, _NODE, addr); // node.point
|
|
addr->net = mainaka->net;
|
|
}
|
|
}
|
|
if(point)
|
|
macro_addr(point+1, _POINT, addr);
|
|
}
|
|
if(domain == NULL)
|
|
domain = str+strlen(str); // point at NUL char
|
|
|
|
return(domain);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static char* make_addr_str(char* str, Addr* addr, char* domain) {
|
|
|
|
char* ptr = str;
|
|
static char buf[20];
|
|
|
|
*ptr = NUL;
|
|
|
|
if(addr->zone) {
|
|
if(addr->zone == GFTN_ALL)
|
|
ptr = stpcpy(ptr, "*");
|
|
else {
|
|
sprintf(buf, "%u", addr->zone);
|
|
ptr = stpcpy(ptr, buf);
|
|
}
|
|
*ptr++ = ':';
|
|
}
|
|
|
|
if(addr->net == GFTN_ALL)
|
|
ptr = stpcpy(ptr, "*");
|
|
else {
|
|
sprintf(buf, "%u", addr->net);
|
|
ptr = stpcpy(ptr, buf);
|
|
}
|
|
*ptr++ = '/';
|
|
|
|
if(addr->node == GFTN_ALL)
|
|
ptr = stpcpy(ptr, "*");
|
|
else {
|
|
sprintf(buf, "%u", addr->node);
|
|
ptr = stpcpy(ptr, buf);
|
|
}
|
|
|
|
if(addr->point) {
|
|
*ptr++ = '.';
|
|
if(addr->point == GFTN_ALL)
|
|
ptr = stpcpy(ptr, "*");
|
|
else {
|
|
sprintf(buf, "%u", addr->point);
|
|
ptr = stpcpy(ptr, buf);
|
|
}
|
|
}
|
|
|
|
if(domain and *domain) {
|
|
*ptr++ = '@';
|
|
ptr = stpcpy(ptr, domain);
|
|
}
|
|
|
|
*ptr = NUL;
|
|
|
|
return(str);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Compare two nodes by name/address/file/pos
|
|
|
|
static bool cmp_nnlsts(const _GEIdx &A, const _GEIdx &B) {
|
|
|
|
int cmp;
|
|
|
|
if((cmp = stricmp(A.name, B.name)) != 0)
|
|
return(cmp < 0);
|
|
if((cmp = CmpV(A.addr.zone, B.addr.zone)) != 0)
|
|
return(cmp < 0);
|
|
if((cmp = CmpV(A.addr.net, B.addr.net)) != 0)
|
|
return(cmp < 0);
|
|
if((cmp = CmpV(A.addr.node, B.addr.node)) != 0)
|
|
return(cmp < 0);
|
|
if((cmp = CmpV(A.addr.point, B.addr.point)) != 0)
|
|
return(cmp < 0);
|
|
if((cmp = CmpV(A.pos, B.pos)) != 0)
|
|
return(cmp < 0);
|
|
return false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Compare two nodes by address/name/file/pos
|
|
|
|
static bool cmp_anlsts(const _GEIdx &A, const _GEIdx &B) {
|
|
|
|
int cmp;
|
|
|
|
if((cmp = CmpV(A.addr.zone, B.addr.zone)) != 0)
|
|
return(cmp < 0);
|
|
if((cmp = CmpV(A.addr.net, B.addr.net)) != 0)
|
|
return(cmp < 0);
|
|
if((cmp = CmpV(A.addr.node, B.addr.node)) != 0)
|
|
return(cmp < 0);
|
|
if((cmp = CmpV(A.addr.point, B.addr.point)) != 0)
|
|
return(cmp < 0);
|
|
if((cmp = stricmp(A.name, B.name)) != 0)
|
|
return(cmp < 0);
|
|
if((cmp = CmpV(A.pos, B.pos)) != 0)
|
|
return(cmp < 0);
|
|
return false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
#if defined(_MSC_VER)
|
|
enum{ sort_by_address=0, sort_by_name } static sort_type;
|
|
bool operator<(const _GEIdx &A, const _GEIdx &B)
|
|
{
|
|
if (sort_type==sort_by_address)
|
|
return cmp_anlsts(A, B);
|
|
else
|
|
return cmp_nnlsts(A, B);
|
|
}
|
|
#endif
|
|
// ------------------------------------------------------------------
|
|
|
|
static char* CvtName(char* inp) {
|
|
|
|
char buf[300];
|
|
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)) = 0;
|
|
strcat(buf, p);
|
|
strcpy(inp, buf);
|
|
}
|
|
struplow(inp);
|
|
return inp;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
#ifdef GOLDNODE_STATS
|
|
void calc_statistic(std::ofstream &ofp, int* observation, float N) {
|
|
|
|
int i;
|
|
float mean = 0.0;
|
|
float sumfrekvens = 0.0;
|
|
float varians = 0.0;
|
|
|
|
// 12 12345 12345 123456 123456789012
|
|
ofp << ".---------------------------------------------." << std::endl
|
|
<< "| x | h(x) | f(x) | x*f(x) | (x-m)^2*f(x) |" << std::endl
|
|
<< "|-----+-------+-------+--------+--------------|" << std::endl;
|
|
|
|
for(i=0; i<100; i++) {
|
|
float x = i;
|
|
if(observation[i]) {
|
|
float hyppighed = observation[i];
|
|
float frekvens = hyppighed / N;
|
|
mean += x * frekvens;
|
|
sumfrekvens += frekvens;
|
|
}
|
|
}
|
|
|
|
for(i=0; i<100; i++) {
|
|
float x = i;
|
|
if(observation[i]) {
|
|
float hyppighed = observation[i];
|
|
float frekvens = hyppighed / N;
|
|
float vartmp = (x-mean)*(x-mean)*frekvens;
|
|
varians += vartmp;
|
|
ofp << "| " << std::setw(3) << i << " | " << std::setw(5) << observation[i] << " | " << std::setprecision(3) << std::setw(5) << frekvens << " | " << std::setw(6) << x*frekvens << " | " << std::setw(12) << vartmp << " | " << std::endl;
|
|
}
|
|
}
|
|
|
|
ofp << "|-----+-------+-------+--------+--------------|" << std::endl
|
|
<< "| sum | " << std::setprecision(0) << std::setw(5) << N << " | " << std::setprecision(3) << std::setw(5) << sumfrekvens << " | " << std::setw(6) << mean << " | " << std::setw(12) << varians << " |" << std::endl
|
|
<< "`---------------------------------------------'" << std::endl
|
|
<< std::endl
|
|
<< "Mean: " << std::setprecision(1) << mean << std::endl
|
|
<< "Variance = " << varians << std::endl
|
|
<< "Standard deviation = " << sqrt(varians) << std::endl
|
|
<< std::endl;
|
|
}
|
|
#endif
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// some useful string operations
|
|
|
|
inline void index_line(char* p, char* ptrs[5]) {
|
|
|
|
for(int i=0; i<5; i++) {
|
|
char* q = p;
|
|
while(*q != ',' and *q) {
|
|
if(*q == '_')
|
|
*q = ' ';
|
|
q++;
|
|
}
|
|
if(*q) {
|
|
ptrs[i] = p;
|
|
*q++ = NUL;
|
|
p = q;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Read the nodelists and userlists
|
|
|
|
static void read_nodelists()
|
|
{
|
|
gfile lfp;
|
|
long pos;
|
|
char* ptr;
|
|
_GEIdx nlst;
|
|
Addr nlstz;
|
|
char buf[512], buf2[100];
|
|
int point;
|
|
uint line, realfno;
|
|
size_t no, nodes;
|
|
const char* name;
|
|
char* lp[5];
|
|
geidxlist nodeidx;
|
|
stamp_iter fno;
|
|
addr_iter zno;
|
|
|
|
nodes = 0;
|
|
|
|
if(not quiet) std::cout << std::endl << "* Compiling nodelists:" << std::endl;
|
|
|
|
// Delete the current indexfiles so they don't take up space
|
|
remove(addrindex.c_str());
|
|
remove(nodeindex.c_str());
|
|
|
|
// Compile nodelists
|
|
for(realfno=0, fno=nodelist.begin(), zno=nodezone.begin(); fno != nodelist.end(); fno++, zno++) {
|
|
|
|
if (nodes < maxnodes)
|
|
{
|
|
lfp.Fopen(fno->fn, "rb", sh_mod);
|
|
if (lfp.isopen())
|
|
{
|
|
lfp.SetvBuf(NULL, _IOFBF, 32000);
|
|
fno->ft = GetFiletime(fno->fn);
|
|
|
|
// Initialize for each nodelist file
|
|
no = 0;
|
|
pos = 0;
|
|
line = 0;
|
|
point = YES;
|
|
nlst.reset();
|
|
nlstz = nlst.addr = *zno;
|
|
name = CleanFilename(fno->fn);
|
|
|
|
// Read all nodes
|
|
while (lfp.Fgets(buf, sizeof(buf)))
|
|
{
|
|
line++;
|
|
|
|
// Break out if eof-marker is found
|
|
if(*buf == '\x1A')
|
|
break;
|
|
|
|
// Note file position
|
|
nlst.pos = pos;
|
|
|
|
// Get line length and fix possible errors
|
|
uint llen = strlen(buf);
|
|
ptr = buf+llen-1;
|
|
while(llen and not (*ptr == '\r' or *ptr == '\n' or *ptr == '\x1A')) {
|
|
buf[llen] = ' ';
|
|
if(not quiet) {
|
|
int len = 16-strlen(name);
|
|
std::cout << "\r* |--" << name << std::setw((len > 0) ? len : 1) << " " << "Warning line " << line << " - Invalid NUL char encountered." << std::endl;
|
|
}
|
|
llen = strlen(buf);
|
|
ptr = buf+llen-1;
|
|
}
|
|
pos += llen;
|
|
|
|
// Skip whitespace
|
|
ptr = buf;
|
|
while(isspace(*ptr))
|
|
ptr++;
|
|
|
|
if(*ptr != ';' and *ptr) {
|
|
|
|
// First test for FD pvt extension
|
|
if(toupper(*ptr) == 'B') { // Boss
|
|
nlst.addr.reset();
|
|
parse_address(ptr+5, &nlst.addr, &nlstz);
|
|
point = YES;
|
|
continue;
|
|
}
|
|
|
|
// Test for Goldware extension
|
|
if(isdigit(*ptr)) {
|
|
nlst.addr.reset();
|
|
parse_address(ptr+5, &nlst.addr, &nlstz);
|
|
point = YES;
|
|
}
|
|
|
|
// Hold,32,TriCom,Hornbaek,Lars_Joergensen,45-12345678,2400,XX
|
|
|
|
// Form the full node address
|
|
index_line(ptr, lp);
|
|
|
|
// NOTE: I use the fact that the third letter in lp[0] is unique
|
|
// for all valid attrs to speed up processing
|
|
|
|
switch(*lp[0] ? toupper(lp[0][2]) : 0) {
|
|
case 'N': // zone
|
|
nlst.addr.zone = nlst.addr.net = atow(lp[1]);
|
|
nlst.addr.node = nlst.addr.point = 0;
|
|
point = NO;
|
|
break;
|
|
|
|
case 'G': // Region
|
|
nlst.addr.net = atow(lp[1]);
|
|
nlst.addr.node = nlst.addr.point = 0;
|
|
point = NO;
|
|
if(nlst.addr.net >= 10000)
|
|
continue;
|
|
break;
|
|
|
|
case 'S': // Host
|
|
{
|
|
nlst.addr.net = atow(lp[1]);
|
|
nlst.addr.node = nlst.addr.point = 0;
|
|
point = NO;
|
|
Addr a;
|
|
fast_parse_addr(lp[2],&a);
|
|
if(a.net) { // Is POINTS24 format ?
|
|
nlst.addr.net = a.net;
|
|
nlst.addr.node = a.node;
|
|
nlst.addr.point = 0;
|
|
point = YES;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'B': // Hub
|
|
nlst.addr.node = atow(lp[1]);
|
|
nlst.addr.point = 0;
|
|
point = NO;
|
|
break;
|
|
|
|
case 'I': // point
|
|
nlst.addr.point = atow(lp[1]);
|
|
break;
|
|
|
|
case 'T': // Pvt
|
|
case 'W': // Down
|
|
case 'L': // Hold
|
|
default:
|
|
if(point)
|
|
nlst.addr.point = atow(lp[1]);
|
|
else {
|
|
nlst.addr.node = atow(lp[1]);
|
|
nlst.addr.point = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(ISTWIRLY(no)) {
|
|
int len = 16-strlen(name);
|
|
std::cout << "\r* \\--" << name << std::setw((len > 0) ? len : 1) << " " << "Zone " << nlst.addr.zone << " \tNet " << nlst.addr.net << " \tNodes " << (uint32_t)no << " " << std::flush;
|
|
}
|
|
|
|
bool include = true;
|
|
|
|
// Check address against the exclude masks
|
|
for(addr_iter n=excludenode.begin(); n != excludenode.end(); n++) {
|
|
if(match_addr_mask(&(*n), &nlst.addr)) {
|
|
include = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check address against the include masks
|
|
if(not include) {
|
|
for(addr_iter n=includenode.begin(); n != includenode.end(); n++) {
|
|
if(match_addr_mask(&(*n), &nlst.addr)) {
|
|
include = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(include) { // Address was okay
|
|
|
|
// Convert name to Goldware standard
|
|
strxcpy(nlst.name, CvtName(lp[4]), sizeof(nlst.name));
|
|
|
|
// Prepare the rest
|
|
nlst.pos |= ((((dword)realfno) << 24) & 0xFF000000L);
|
|
|
|
// Append to end of list
|
|
nodeidx.push_back(nlst);
|
|
++nodes;
|
|
|
|
// Count the node
|
|
no++;
|
|
|
|
// Stop if limit is reached
|
|
if(nodes >= maxnodes)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(not quiet) {
|
|
int len = 16-strlen(name);
|
|
std::cout << "\r* " << ((fno == nodelist.end()-1) ? '\\' : '|') << "--" << name << std::setw((len > 0) ? len : 1) << " " << "Nodes read: " << (uint32_t)no << "\tTotal read: " << (uint32_t)nodes << ((nodes >= maxnodes) ? " (Limit reached)" : " ") << std::endl;
|
|
}
|
|
|
|
lfp.Fclose();
|
|
++realfno;
|
|
}
|
|
else {
|
|
if(not quiet) std::cout << "Error opening nodelist " << fno->fn << '!' << std::endl;
|
|
*(fno->fn) = NUL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compile userlists
|
|
if(userlist.size()) {
|
|
if(not quiet) std::cout << std::endl << "* Compiling userlists:" << std::endl;
|
|
}
|
|
|
|
pos = 0;
|
|
|
|
for(fno=userlist.begin(), zno=userzone.begin(); fno != userlist.end() and nodes < maxnodes; fno++, zno++) {
|
|
|
|
no = 0;
|
|
|
|
lfp.Fopen(fno->fn, "rt", sh_mod);
|
|
if (lfp.isopen())
|
|
{
|
|
lfp.SetvBuf(NULL, _IOFBF, 32000);
|
|
|
|
name = CleanFilename(fno->fn);
|
|
|
|
if (nodes < maxnodes)
|
|
{
|
|
while (lfp.Fgets(buf, sizeof(buf)))
|
|
{
|
|
// Get node data
|
|
strbtrim(buf);
|
|
ptr = buf + strlen(buf) - 1;
|
|
while(*ptr != ' ')
|
|
ptr--;
|
|
nlst.reset();
|
|
nlst.addr = *zno;
|
|
fast_parse_addr(ptr+1, &nlst.addr);
|
|
*ptr = NUL;
|
|
strbtrim(buf);
|
|
|
|
// Convert "lastname, firstname" to "firstname lastname"
|
|
ptr = strchr(buf, ',');
|
|
if(ptr) {
|
|
*ptr++ = NUL;
|
|
strxmerge(buf2, 100, strskip_wht(ptr), " ", buf, NULL);
|
|
ptr = buf2;
|
|
}
|
|
else {
|
|
ptr = buf;
|
|
}
|
|
|
|
// Convert name to Goldware standard
|
|
strxcpy(nlst.name, CvtName(ptr), sizeof(nlst.name));
|
|
|
|
bool include = true;
|
|
|
|
// Check address against the exclude masks
|
|
for(addr_iter n=excludenode.begin(); n != excludenode.end(); n++) {
|
|
if(match_addr_mask(&(*n), &nlst.addr)) {
|
|
include = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check address against the include masks
|
|
if(not include) {
|
|
for(addr_iter n=includenode.begin(); n != includenode.end(); n++) {
|
|
if(match_addr_mask(&(*n), &nlst.addr)) {
|
|
include = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(include) { // Address was okay
|
|
|
|
if(ISTWIRLY(nodes)) {
|
|
int len = 16-strlen(name);
|
|
std::cout << "\r* \\--" << name << std::setw((len > 0) ? len : 1) << " " << "Nodes: " << (uint32_t)nodes << " " << std::flush;
|
|
}
|
|
|
|
// Indicate userlist
|
|
nlst.pos = (long)0xFF000000L | (pos++);
|
|
|
|
// Append to end of list
|
|
nodeidx.push_back(nlst);
|
|
++nodes;
|
|
|
|
// Count the node
|
|
no++;
|
|
|
|
// Stop if limit is reached
|
|
if(nodes >= maxnodes)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(not quiet) {
|
|
int len = 16-strlen(name);
|
|
std::cout << "\r* " << ((fno == userlist.end()-1) ? '\\' : '|') << "--" << name << std::setw((len > 0) ? len : 1) << " " << "Nodes read: " << (uint32_t)no << "\tTotal read: " << (uint32_t)nodes << ((nodes >= maxnodes) ? " (Limit reached)" : " ") << std::endl;
|
|
}
|
|
|
|
lfp.Fclose();
|
|
}
|
|
else {
|
|
if(not quiet) std::cout << "Error opening userlist " << fno->fn << '!' << std::endl;
|
|
}
|
|
}
|
|
|
|
#ifdef GOLDNODE_STATS
|
|
if(make_stats) {
|
|
|
|
if(not quiet) std::cout << "* Writing statistics to " << statfilename << NL;
|
|
|
|
std::ofstream ofp(statfilename);
|
|
if(not ofp) {
|
|
if(not quiet) std::cout << "Error opening statfile " << statfilename << '!' << NL;
|
|
}
|
|
else {
|
|
ofp << "Nodename size statistics:" << std::endl;
|
|
calc_statistic(ofp, statistic.nodename, nodes);
|
|
|
|
ofp << std::endl << "Location size statistics:" << std::endl;
|
|
calc_statistic(ofp, statistic.location, nodes);
|
|
|
|
ofp << std::endl << "Sysopname size statistics:" << std::endl;
|
|
calc_statistic(ofp, statistic.sysopname, nodes);
|
|
}
|
|
}
|
|
else {
|
|
#endif
|
|
// At last, sort the nodes
|
|
geidxlist::iterator curr, prev;
|
|
std::map<long, dword> namepos;
|
|
|
|
// Sort by name
|
|
if(not quiet) std::cout << NL << "* Sorting by name " << std::flush;
|
|
#if defined(_MSC_VER)
|
|
sort_type = sort_by_name;
|
|
nodeidx.sort();
|
|
#else
|
|
nodeidx.sort(cmp_nnlsts);
|
|
#endif
|
|
// Write the name-sorted .GXN
|
|
gfile fp(nodeindex.c_str(), "wb", sh_mod);
|
|
if (fp.isopen())
|
|
{
|
|
name = CleanFilename(nodeindex.c_str());
|
|
|
|
gfile fido;
|
|
if (fidouser) fido.Fopen(fidouserlst, "wt", sh_mod);
|
|
|
|
if (!fido.isopen())
|
|
{
|
|
if(not quiet) std::cout << "\b, writing " << name << ' ' << std::flush;
|
|
fidouser = false;
|
|
}
|
|
else {
|
|
if(not quiet) std::cout << "\b, writing " << name << " and " << fidouserlst << ' ' << std::flush;
|
|
}
|
|
|
|
int nn = 0;
|
|
dword nodenum = 0;
|
|
for(prev = nodeidx.end(), curr = nodeidx.begin(); curr != nodeidx.end(); prev = curr++) {
|
|
|
|
if(ISTWIRLY(nn++))
|
|
twirly();
|
|
|
|
if(ignoredups) {
|
|
if(prev != nodeidx.end() && match_addr_mask(&curr->addr, &prev->addr)) {
|
|
if(strieql(curr->name, prev->name)) {
|
|
#ifdef DEBUG
|
|
if(not quiet) std::cout << "* Dupe: " << curr->addr.zone << ':' << curr->addr.net << '/' << curr->addr.node << '.' << curr->addr.point << ' ' << curr->name << NL;
|
|
#endif
|
|
nodeidx.erase(curr);
|
|
curr = prev;
|
|
++dups;
|
|
continue;
|
|
}
|
|
}
|
|
fp.Fwrite(&(*curr), sizeof(_GEIdx));
|
|
}
|
|
else
|
|
fp.Fwrite(&(*curr), sizeof(_GEIdx));
|
|
|
|
namepos[curr->pos] = nodenum++;
|
|
if (fidouser)
|
|
{
|
|
char buf[256];
|
|
fido.Printf("%-36.36s%24.24s\n", curr->name, make_addr_str(buf, &curr->addr, ""));
|
|
}
|
|
}
|
|
|
|
fp.Fclose();
|
|
}
|
|
|
|
// Sort by address
|
|
if(not quiet) std::cout << ' ' << NL "* Sorting by node " << std::flush;
|
|
#if defined(_MSC_VER)
|
|
sort_type = sort_by_address;
|
|
nodeidx.sort();
|
|
#else
|
|
nodeidx.sort(cmp_anlsts);
|
|
#endif
|
|
|
|
// Write the address-sorted .GXA
|
|
fp.Fopen(addrindex.c_str(), "wb", sh_mod);
|
|
if (fp.isopen())
|
|
{
|
|
name = CleanFilename(addrindex.c_str());
|
|
if(not quiet) std::cout << "\b, writing " << name << ' ' << std::flush;
|
|
int nn = 0;
|
|
for(curr = nodeidx.begin(); curr != nodeidx.end(); curr++) {
|
|
if(ISTWIRLY(nn++))
|
|
twirly();
|
|
fp.Fwrite(&namepos[curr->pos], sizeof(dword));
|
|
}
|
|
fp.Fclose();
|
|
}
|
|
|
|
// Write the list index in .GXL
|
|
fp.Fopen(listindex.c_str(), "wt", sh_mod);
|
|
if (fp.isopen())
|
|
{
|
|
name = CleanFilename(listindex.c_str());
|
|
if (not quiet) std::cout << ' ' << NL "* Writing " << name << std::endl;
|
|
for (fno=nodelist.begin(); fno != nodelist.end(); fno++)
|
|
{
|
|
if (*(fno->fn))
|
|
fp.Printf("%s %u\n", fno->fn, fno->ft);
|
|
}
|
|
|
|
fp.Fclose();
|
|
}
|
|
|
|
// Note compile time
|
|
runtime = gtime(NULL) - runtime;
|
|
|
|
if(not quiet) {
|
|
if(dups) {
|
|
std::cout << NL "* Total duplicate nodes: " << (uint32_t)dups << '.' << NL;
|
|
}
|
|
std::cout << NL "* Nodelist compile completed. Compile time: " << (uint32_t)(runtime/60) << " min, " << (uint32_t)(runtime%60) << " sec." << NL;
|
|
}
|
|
#ifdef GOLDNODE_STATS
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static void check_nodelists(bool force)
|
|
{
|
|
uint n;
|
|
int compilen, compileu;
|
|
static Path buf, newpath;
|
|
|
|
// Find newest nodelists
|
|
for(n=0,compilen=0; n<nodelist.size(); n++) {
|
|
|
|
strcpy(buf, CleanFilename(nodelist[n].fn));
|
|
char *ext = strchr(buf, '.');
|
|
if(ext and ((atoi(ext+1) == 999) or (ext[1] == '*'))) {
|
|
extractdirname(newpath, nodelist[n].fn);
|
|
int extpos = ext-buf+1;
|
|
strcpy(ext, ".*");
|
|
gposixdir f(newpath);
|
|
const gdirentry *de;
|
|
time32_t listtime = 0;
|
|
bool listdefined = false;
|
|
while((de = f.nextentry(buf)) != NULL)
|
|
if(atoi(de->name.c_str()+extpos)) {
|
|
if(not listdefined or (de->stat_info.st_mtime-listtime > 0)) {
|
|
listtime = de->stat_info.st_mtime;
|
|
listdefined = true;
|
|
strxmerge(nodelist[n].fn, sizeof(Path), newpath, de->name.c_str(), NULL);
|
|
}
|
|
}
|
|
strchg(nodelist[n].fn, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
|
|
}
|
|
}
|
|
|
|
// Get timestamps from .GXL file
|
|
gfile fp(listindex.c_str(), "rt", sh_mod);
|
|
if (fp.isopen())
|
|
{
|
|
while (fp.Fgets(buf, sizeof(buf)))
|
|
{
|
|
char* key;
|
|
char* val=buf;
|
|
getkeyval(&key, &val);
|
|
key = strxcpy(newpath, strbtrim(key), sizeof(Path));
|
|
_MapPath(key);
|
|
strchg(key, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
|
|
for(n=0; n<nodelist.size(); n++) {
|
|
if(strieql(nodelist[n].fn, key)) {
|
|
nodelist[n].ft = atol(val);
|
|
break;
|
|
}
|
|
}
|
|
for(n=0; n<userlist.size(); n++) {
|
|
if(strieql(userlist[n].fn, key)) {
|
|
userlist[n].ft = atol(val);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fp.Fclose();
|
|
} else
|
|
perror("error opening .gxl file");
|
|
|
|
// Check nodelists
|
|
for(n=0,compilen=0; n<nodelist.size(); n++) {
|
|
if(abs(long(GetFiletime(nodelist[n].fn) - nodelist[n].ft)) > 1) {
|
|
nodelist[n].fc = YES;
|
|
compilen++;
|
|
}
|
|
}
|
|
|
|
if(not quiet) {
|
|
if(compilen) {
|
|
std::cout << "* " << compilen << " new nodelist file" << ((compilen == 1) ? "" : "s") << " found." NL;
|
|
}
|
|
else if(nodelist.size()) {
|
|
std::cout << "* The nodelist file" << ((nodelist.size() == 1) ? " is" : "s are") << " up-to-date." NL;
|
|
}
|
|
}
|
|
|
|
// Check userlists
|
|
for(n=0,compileu=0; n<userlist.size(); n++) {
|
|
if(abs(long(GetFiletime(newpath) - userlist[n].ft)) > 1) {
|
|
userlist[n].fc = YES;
|
|
compileu++;
|
|
}
|
|
}
|
|
|
|
if(not quiet) {
|
|
if(compileu) {
|
|
std::cout << "* " << compileu << " new userlist file" << ((compileu == 1) ? "" : "s") << " found." NL;
|
|
}
|
|
else if(userlist.size()) {
|
|
std::cout << "* The userlist file" << ((userlist.size() == 1) ? " is" : "s are") << " up-to-date." NL;
|
|
}
|
|
}
|
|
|
|
if(force or compilen or compileu)
|
|
read_nodelists();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static void fatal_error(const char* what) {
|
|
|
|
if(not quiet) std::cout << what << NL;
|
|
exit(5);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static int do_if(char* val) {
|
|
|
|
if(strieql(val, "OS/2") or strieql(val, "OS2")) {
|
|
#ifdef __OS2__
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
else if(strieql(val, "NT") or strieql(val, "W32") or strieql(val, "WIN32")) {
|
|
#ifdef __WIN32__
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
else if(strieql(val, "386") or strieql(val, "DOS") or strieql(val, "DPMI32")) {
|
|
#ifdef __MSDOS__
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
else if(strieql(val, "LINUX") or strieql(val, "UNIX")) {
|
|
#ifdef __UNIX__
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
else if (strieql(val, "SPELL"))
|
|
{
|
|
#ifdef GCFG_SPELL_INCLUDED
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
else if(strieql(val, "FIREBIRD"))
|
|
return true;
|
|
else if(strieql(val, "ASA") or strieql(val, "PLUS"))
|
|
return true;
|
|
else if(strieql(val, "YES") or strieql(val, "TRUE") or strieql(val, "ON"))
|
|
return true;
|
|
return !!atoi(val);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
char* _MapPath(char* fmap, bool reverse) {
|
|
|
|
Path buf, cmap;
|
|
|
|
strxcpy(cmap, fmap, sizeof(Path));
|
|
if(reverse)
|
|
strchg(cmap, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
|
|
|
|
std::vector< std::pair<std::string, std::string> >::iterator i;
|
|
for(i = mappath.begin(); i != mappath.end(); i++) {
|
|
const char* p = reverse ? i->second.c_str() : i->first.c_str();
|
|
const char* q = reverse ? i->first.c_str() : i->second.c_str();
|
|
if(strnieql(cmap, p, strlen(p))) {
|
|
strxcpy(buf, fmap, sizeof(Path));
|
|
strxmerge(fmap, sizeof(Path), q, buf+strlen(p), NULL);
|
|
char sl1, sl2;
|
|
const char* ptr;
|
|
|
|
ptr = strpbrk(p, "/\\");
|
|
sl1 = ptr ? *ptr : NUL;
|
|
ptr = strpbrk(q, "/\\");
|
|
sl2 = ptr ? *ptr : NUL;
|
|
|
|
if(sl1 and sl2 and (sl1 != sl2))
|
|
strchg(fmap, sl1, sl2);
|
|
|
|
break;
|
|
}
|
|
}
|
|
return fmap;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static int parse_config(const char *__configfile, Addr& zoneaddr)
|
|
{
|
|
char buf[512];
|
|
char* ptr;
|
|
char* key;
|
|
word crc;
|
|
char* value;
|
|
char* value2;
|
|
int _gotcond,line = 0;
|
|
static int in_if = NO;
|
|
static int in_else = NO;
|
|
static int cond_status = YES;
|
|
|
|
gfile fp(__configfile, "rt", sh_mod);
|
|
if (fp.isopen())
|
|
{
|
|
while (fp.Fgets((ptr=buf), sizeof(buf)))
|
|
{
|
|
line++;
|
|
// Replace TABs with SPACEs
|
|
ptr = strskip_wht(ptr);
|
|
if(*ptr != ';' and *ptr) {
|
|
crc=getkeyvalcrc(&key, &ptr);
|
|
getkeyval(&value, &ptr);
|
|
getkeyval(&value2, &ptr);
|
|
|
|
_gotcond = YES;
|
|
switch(crc) {
|
|
case CRC_IF:
|
|
if(in_if) {
|
|
if(not quiet) std::cout << "* " << __configfile << ": Misplaced IF at line " << line << ". IF's cannot be nested." << NL;
|
|
}
|
|
in_if = YES;
|
|
cond_status = do_if(value);
|
|
break;
|
|
case CRC_ELIF:
|
|
case CRC_ELSEIF:
|
|
if((not in_if) or in_else) {
|
|
if(not quiet) std::cout << "* " << __configfile << ": Misplaced ELIF/ELSEIF at line " << line << '.' << NL;
|
|
}
|
|
cond_status = do_if(value);
|
|
break;
|
|
case CRC_ELSE:
|
|
if((not in_if) or in_else) {
|
|
if(not quiet) std::cout << "* " << __configfile << "Misplaced ELSE at line " << line << '.' << NL;
|
|
}
|
|
in_else = YES;
|
|
cond_status ^= YES;
|
|
break;
|
|
case CRC_ENDIF:
|
|
if(not in_if) {
|
|
if(not quiet) std::cout << "* " << __configfile << ": Misplaced ENDIF at line " << line << '.' << NL;
|
|
}
|
|
in_if = in_else = NO;
|
|
cond_status = YES;
|
|
break;
|
|
default:
|
|
_gotcond = NO;
|
|
break;
|
|
}
|
|
|
|
if((not _gotcond) and cond_status) {
|
|
switch(crc) {
|
|
case CRC_NODEPATH:
|
|
_MapPath(value);
|
|
PathCopy(nodepath, value);
|
|
break;
|
|
case CRC_ADDRESS:
|
|
case CRC_AKA:
|
|
if(not zoneaddr.net) {
|
|
parse_address(value, &zoneaddr, &zoneaddr);
|
|
zoneaddr.point = 0;
|
|
}
|
|
break;
|
|
case CRC_NODELIST:
|
|
{
|
|
Stamp ndl;
|
|
Addr ndz;
|
|
|
|
if(atoi(value2)) {
|
|
parse_address(value2, &ndz, &ndz);
|
|
if(ndz.zone == 0) {
|
|
ndz.zone = ndz.node;
|
|
ndz.net = 0;
|
|
ndz.node = 0;
|
|
}
|
|
}
|
|
else
|
|
ndz = zoneaddr;
|
|
ndz.point = 0;
|
|
ndl.ft = (dword)-1;
|
|
ndl.fc = NO;
|
|
strschg_environ(value);
|
|
_MapPath(value);
|
|
strcpy(ndl.fn, value);
|
|
nodelist.push_back(ndl);
|
|
nodezone.push_back(ndz);
|
|
}
|
|
break;
|
|
case CRC_USERLIST:
|
|
{
|
|
Stamp ndl;
|
|
Addr ndz;
|
|
|
|
if(atoi(value2)) {
|
|
parse_address(value2, &ndz, &ndz);
|
|
if(ndz.zone == 0) {
|
|
ndz.zone = ndz.node;
|
|
ndz.net = 0;
|
|
ndz.node = 0;
|
|
}
|
|
}
|
|
else
|
|
ndz = zoneaddr;
|
|
ndz.point = 0;
|
|
ndl.ft = (dword)-1;
|
|
ndl.fc = NO;
|
|
strschg_environ(value);
|
|
_MapPath(value);
|
|
strcpy(ndl.fn, value);
|
|
userlist.push_back(ndl);
|
|
userzone.push_back(ndz);
|
|
}
|
|
break;
|
|
case CRC_EXCLUDENODES:
|
|
{
|
|
Addr exn;
|
|
parse_address(value, &exn, &zoneaddr);
|
|
excludenode.push_back(exn);
|
|
}
|
|
break;
|
|
case CRC_INCLUDENODES:
|
|
{
|
|
Addr inn;
|
|
parse_address(value, &inn, &zoneaddr);
|
|
includenode.push_back(inn);
|
|
}
|
|
break;
|
|
case CRC_SHAREMODE:
|
|
if(atoi(value))
|
|
sh_mod = atoi(value);
|
|
else
|
|
sh_mod = GetYesno(value) ? SH_DENYNO : SH_COMPAT;
|
|
break;
|
|
case CRC_INCLUDE:
|
|
strschg_environ(value);
|
|
_MapPath(value);
|
|
if(not parse_config(value,zoneaddr)) // NOTE! This is a recursive call!
|
|
if(not quiet) std::cout << "* Could not read configuration file " << value << '!' << NL;
|
|
break;
|
|
case CRC_MAPPATH:
|
|
{
|
|
std::pair<std::string, std::string> mapentry;
|
|
|
|
mapentry.first = value;
|
|
mapentry.second = value2;
|
|
mappath.push_back(mapentry);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(YES);
|
|
}
|
|
else {
|
|
return(NO);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static bool ExistCfg(char* path, char* file) {
|
|
|
|
bool found = fexist(AddPath(path, file));
|
|
if(found)
|
|
strcat(path, file);
|
|
return found;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static bool FindCfg(char* path) {
|
|
|
|
bool found = false;
|
|
|
|
if(!is_dir(path)) {
|
|
if(fexist(path))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
AddBackslash(path);
|
|
#if defined(__OS2__)
|
|
found = ExistCfg(path, "ged2.cfg");
|
|
#elif defined(__WIN32__)
|
|
found = ExistCfg(path, "gedw32.cfg");
|
|
#endif
|
|
if(not found)
|
|
found = ExistCfg(path, "golded.cfg");
|
|
return found;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static bool read_config(const char *cfg, const char *argv_0) {
|
|
|
|
Addr zoneaddr;
|
|
Path buf;
|
|
|
|
bool found = (*cfg != NUL);
|
|
if(not found) {
|
|
// Look for configfilename in the environment
|
|
const char *ptr = getenv("GOLDNODE");
|
|
#if defined(__OS2__)
|
|
if(not(ptr and *ptr))
|
|
ptr = getenv("GED2");
|
|
#elif defined(__WIN32__)
|
|
if(not(ptr and *ptr))
|
|
ptr = getenv("GEDW32");
|
|
#endif
|
|
if(not(ptr and *ptr))
|
|
ptr = getenv("GOLDED");
|
|
if(not(ptr and *ptr))
|
|
ptr = getenv("GED");
|
|
if(ptr and *ptr) {
|
|
strxcpy(buf, ptr, sizeof(buf));
|
|
found = FindCfg(buf);
|
|
}
|
|
|
|
// Get it in current directory
|
|
if(not found) {
|
|
getcwd(buf, sizeof(buf));
|
|
found = FindCfg(buf);
|
|
}
|
|
|
|
// Get it where the the .EXE file is
|
|
if(not found) {
|
|
extractdirname(buf, argv_0);
|
|
found = FindCfg(buf);
|
|
|
|
// If we still could not find config name...
|
|
if(not found)
|
|
strcat(buf, "golded.cfg");
|
|
}
|
|
}
|
|
else
|
|
strxcpy(buf, cfg, sizeof(Path));
|
|
|
|
nodelist.clear();
|
|
nodezone.clear();
|
|
userlist.clear();
|
|
userzone.clear();
|
|
mappath.clear();
|
|
if(not parse_config(buf, zoneaddr)) {
|
|
errorlevel = 1;
|
|
return false;
|
|
}
|
|
|
|
if(nodelist.empty() and userlist.empty() == 0)
|
|
fatal_error("* Error: No NODELISTs or USERLISTs defined!");
|
|
|
|
if(zoneaddr.net == 0)
|
|
fatal_error("* Error: No ADDRESS or AKAs defined!");
|
|
|
|
if(nodepath.empty())
|
|
nodepath = getcwd(buf, sizeof(buf));
|
|
|
|
AddBackslash(nodepath);
|
|
MakePathname(listindex, nodepath, "goldnode.gxl");
|
|
MakePathname(nodeindex, nodepath, "goldnode.gxn");
|
|
MakePathname(addrindex, nodepath, "goldnode.gxa");
|
|
size_t n;
|
|
for(n=0; n<nodelist.size(); n++)
|
|
MakePathname(nodelist[n].fn, nodepath.c_str(), nodelist[n].fn);
|
|
for(n=0; n<userlist.size(); n++)
|
|
MakePathname(userlist[n].fn, nodepath.c_str(), userlist[n].fn);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static void run_gn(int argc, char* argv[]) {
|
|
|
|
int n;
|
|
char* ptr;
|
|
bool force=false, conditional=false;
|
|
|
|
// Note start time
|
|
runtime = time(NULL);
|
|
|
|
const char *cfg = "";
|
|
|
|
for(n=1; n<argc; n++) {
|
|
if(strchr("-", *argv[n])) {
|
|
ptr = argv[n]+2;
|
|
if(*ptr == '=')
|
|
ptr++;
|
|
switch(toupper(argv[n][1])) {
|
|
|
|
case 'C':
|
|
conditional = true;
|
|
break;
|
|
|
|
case 'D':
|
|
ignoredups = true;
|
|
break;
|
|
|
|
case 'F':
|
|
force = true;
|
|
break;
|
|
|
|
case 'Q':
|
|
quiet = true;
|
|
break;
|
|
|
|
#ifdef GOLDNODE_STATS
|
|
case 'T':
|
|
make_stats = true;
|
|
break;
|
|
#endif
|
|
|
|
case 'U':
|
|
fidouser = true;
|
|
strcpy(fidouserlst, ptr);
|
|
break;
|
|
|
|
}
|
|
}
|
|
else
|
|
cfg = argv[n];
|
|
}
|
|
|
|
if(not quiet) {
|
|
std::cout << __gver_name__ << " Nodelist Compiler v." << __gver_shortver__ << __gver_platform__ << __gver_postversion__ << "." NL
|
|
<< "Copyright (C) 1990-1999 Odinn Sorensen" NL
|
|
<< "Copyright (C) 1999-2001 Alexander S. Aganichev" NL
|
|
<< "Copyright (C) 2005 Stas Degteff & Golded+ team" NL
|
|
<< "-------------------------------------------------------------------------------\n" NL;
|
|
}
|
|
|
|
if(not(force or conditional)) {
|
|
if(not quiet) {
|
|
std::cout << "Commandline syntax: " << CleanFilename(argv[0]) << " [-options] [configfile]" NL
|
|
<< "\n[-options] =\t-C\t Conditional compile." NL
|
|
<< "\t\t-F\t Forced compile." NL
|
|
<< "\t\t-D\t Remove duplicate nodes from index while compiling." NL
|
|
<< "\t\t-Q\t Quiet compile. No screen output improves speed." NL
|
|
<< "\t\t-S<size> Set max size of a name in the index." NL
|
|
<< "\t\t-U<file> Create sorted FIDOUSER.LST userlist file." NL
|
|
#ifdef GOLDNODE_STATS
|
|
<< "\t\t-T\t Make statistics." NL
|
|
#endif
|
|
<< "\n[configfile] =\t\t The path AND filename of GOLDED.CFG" NL
|
|
<< "\t\t\t configuration file to read.\n" NL;
|
|
}
|
|
}
|
|
else {
|
|
|
|
if(force)
|
|
if(not quiet) std::cout << "* Forced compile." NL;
|
|
|
|
if(read_config(cfg, argv[0])) {
|
|
if(force or conditional)
|
|
check_nodelists(force);
|
|
}
|
|
else {
|
|
if(not quiet) std::cout << NL "Could not find the configuration file!" NL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
throw_init();
|
|
|
|
// set locale
|
|
setlocale(LC_CTYPE, "");
|
|
#if defined(GUTLOS_FUNCS)
|
|
g_init_os(0);
|
|
#endif
|
|
|
|
#ifdef GOLDNODE_STATS
|
|
memset(&statistic, 0, sizeof(nl_stat));
|
|
#endif
|
|
|
|
run_gn(argc, argv);
|
|
|
|
#if defined(GUTLOS_FUNCS)
|
|
g_deinit_os();
|
|
#endif
|
|
|
|
THROW_CHECK();
|
|
|
|
return errorlevel;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|