1 
2 //  ------------------------------------------------------------------
3 //  The Goldware Utilities.
4 //  Copyright (C) 1990-1999 Odinn Sorensen
5 //  Copyright (C) 1999-2001 Alexander S. Aganichev
6 //  Copyright (C) 2005 Stas Degteff
7 //  ------------------------------------------------------------------
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU General Public License as
10 //  published by the Free Software Foundation; either version 2 of the
11 //  License, or (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  General Public License for more details.
17 //
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program; if not, write to the Free Software
20 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 //  ------------------------------------------------------------------
22 //  $Id: goldnode.cpp,v 1.29 2011/02/17 23:22:23 stas_degteff Exp $
23 //  ------------------------------------------------------------------
24 //  GoldNODE - A nodelist compiler for GoldED.
25 //  ------------------------------------------------------------------
26 
27 // using namespace std;
28 
29 #include <gdbgerr.h>
30 #include <list>
31 #include <map>
32 #include <clocale>
33 #include <gdefs.h>
34 #include <gcrcall.h>
35 #include <gmemall.h>
36 #include <gfilutil.h>
37 #include <gftnall.h>
38 #include <gftnnlge.h>
39 #include <gstrall.h>
40 #include <gshare.h>
41 #include <gtimall.h>
42 #include <gutlmisc.h>
43 #include <gccfgg.h>
44 #include <gdirposx.h>
45 #include <gutlos.h>
46 #include <glog.h>
47 #include <iomanip>
48 #include <iostream>
49 #include <fstream>
50 
51 #define GOLDNODE_STATS 1
52 
53 #ifdef GOLDNODE_STATS
54 #include <math.h>
55 #endif
56 
57 #include <golded3.h>
58 #include <gmemdbg.h>
59 
60 //  ------------------------------------------------------------------
61 //  Config versions
62 
63 #define __GVER_NAME__ "GoldNode+"
64 #define __GVER_SHORTNAME__ "GN"
65 #define __gver_name__ __GVER_NAME__
66 #define __gver_shortname__ __GVER_SHORTNAME__
67 
68 //  ------------------------------------------------------------------
69 // 32-bit versions
70 
71 const size_t maxnodes = 262000;
72 
73 
74 //  ------------------------------------------------------------------
75 
76 typedef std::vector<Addr>::iterator addr_iter;
77 typedef std::vector<Stamp>::iterator stamp_iter;
78 
79 #if (_MSC_VER == 1200)
80 class _geidxlist : public std::list<_GEIdx>
81 {
82 public:
sort()83   void sort()
84   {
85     if (2 <= size())
86     {
87       const size_t _MAXN = 15;
88       _Myt _X(allocator), _A[_MAXN + 1];
89       size_t _N = 0;
90 
91       while (!empty())
92       {
93         _X.splice(_X.begin(), *this, begin());
94         size_t _I;
95 
96         for (_I = 0; _I < _N && !_A[_I].empty(); ++_I)
97         {
98           _A[_I].merge(_X);
99           _A[_I].swap(_X);
100         }
101 
102         if (_I == _MAXN) _A[_I].merge(_X);
103         else
104         {
105           _A[_I].swap(_X);
106           if (_I == _N) ++_N;
107         }
108       }
109 
110       for (int _NN = _N; _NN >= 0; _NN--)
111         merge(_A[_NN]);
112     }
113   }
114 };
115 
116 typedef _geidxlist geidxlist;
117 #else
118 typedef std::list<_GEIdx> geidxlist;
119 #endif
120 
121 // Nodelists
122 std::vector<Stamp> nodelist; // nodelist files,stamps,update marker
123 std::vector<Addr> nodezone;  // nodelist zones
124 std::vector<Stamp> userlist; // Userlist files,stamps,update marker
125 std::vector<Addr> userzone;  // Userlist zones
126 std::vector< std::pair<std::string, std::string> > mappath;
127 
128 // Exclude/Include nodes
129 std::vector<Addr> excludenode;
130 std::vector<Addr> includenode;
131 
132 // Index files
133 std::string  addrindex;
134 std::string  nodeindex;
135 std::string  listindex;
136 
137 //  ------------------------------------------------------------------
138 
139 const word _POINT = 0x0001;
140 const word _NODE  = 0x0002;
141 const word _NET   = 0x0003;
142 const word _ZONE  = 0x0004;
143 const word _TEST  = 777;
144 
145 static std::string nodepath;                // Path to the nodelist files
146 
147 static time32_t runtime = 0;
148 static int    sh_mod = SH_DENYWR;
149 static bool   fidouser = false;
150 static Path   fidouserlst;
151 static bool   ignoredups = false;
152 static size_t dups = 0;
153 static bool   quiet = false;
154 
155 #ifdef GOLDNODE_STATS
156 bool make_stats = false;
157 Path statfilename = "goldnode.stt";
158 
159 struct nl_stat {
160   int nodename[100];
161   int location[100];
162   int sysopname[100];
163 };
164 
165 nl_stat statistic;
166 #endif
167 
168 char* _MapPath(char* map, bool reverse = false);
169 
170 //  ------------------------------------------------------------------
171 //  Display a "twirly"
172 
173 #define TWIRLY_FACTOR 511
174 #define ISTWIRLY(n) (not quiet and (((n)&TWIRLY_FACTOR)==0))
175 
twirly()176 static void twirly() {
177 
178   static int n=0;
179 
180   n = (++n)%4;
181   switch(n) {
182     case 0: std::cout << "|\b" << std::flush; break;
183     case 1: std::cout << "/\b" << std::flush; break;
184     case 2: std::cout << "-\b" << std::flush; break;
185     case 3: std::cout << "\\\b" << std::flush; break;
186   }
187 }
188 
189 
190 //  ------------------------------------------------------------------
191 
match_addr_mask(Addr * mask,Addr * addr)192 static bool match_addr_mask(Addr* mask, Addr* addr) {
193 
194   if(mask->zone == GFTN_ALL or mask->zone == addr->zone)
195     if(mask->net == GFTN_ALL or mask->net == addr->net)
196       if(mask->node == GFTN_ALL or mask->node == addr->node)
197         if(mask->point == GFTN_ALL or mask->point == addr->point)
198           return true;
199 
200   return false;
201 }
202 
203 
204 //  ------------------------------------------------------------------
205 
macro_addr(char * str,int ap,Addr * addr)206 static bool macro_addr(char* str, int ap, Addr* addr) {
207 
208   word part = 0xFFFD;
209 
210   if(*str == NUL)
211     part = 0;
212   else if(isdigit(*str))
213     part = atow(str);
214   else if(*str == '?' or *str == '*')
215     part = GFTN_ALL;
216 
217   if(ap == _TEST) {
218     if(part == 0xFFFD)
219       return false;
220     else
221       return true;
222   }
223 
224   switch(ap) {
225     case _ZONE:
226       addr->zone = part;
227       break;
228     case _NET:
229       addr->net = part;
230       break;
231     case _NODE:
232       addr->node = part;
233       break;
234     case _POINT:
235       addr->point = part;
236       break;
237     default:
238       return false;
239   }
240   return true;
241 }
242 
243 
244 //  ------------------------------------------------------------------
245 
fast_parse_addr(char * str,Addr * addr)246 static char* fast_parse_addr(char* str, Addr* addr) {
247 
248   char* net;
249   char* node;
250   char* point;
251   char* domain;
252   char* space;
253 
254   space = strchr(str, ' ');
255   if(space)
256     *space = NUL;
257 
258   net = strchr(str, ':');
259   node = strchr(str, '/');
260   point = strchr(str, '.');
261   domain = strchr(str, '@');
262   if(domain and point)
263     if(point > domain)
264       point = NULL;
265 
266   if(space)
267     *space = ' ';
268 
269   if(net) {
270     addr->zone = atow(str);
271     addr->net = atow(net+1);
272     if(node)
273       addr->node = atow(node+1);
274   }
275   else {
276     if(node) {
277       if(*str != '/')
278         addr->net = atow(str);
279       addr->node = atow(node+1);
280     }
281     else {
282       if(point != str)
283         addr->node = atow(str);
284     }
285   }
286   if(point)
287     addr->point = atow(point+1);
288 
289   return domain;
290 }
291 
292 
293 //  ------------------------------------------------------------------
294 
parse_address(char * str,Addr * addr,Addr * mainaka)295 static char* parse_address(char* str, Addr* addr, Addr* mainaka) {
296 
297   char* domain = NULL;
298 
299   str = strskip_wht(str);
300 
301   if(isdigit(*str) or *str == '.' or macro_addr(str, _TEST, addr)) {
302 
303     char* net = strchr(str, ':');
304     char* node = strchr(str, '/');
305     char* point = strchr(str, '.');
306     domain = strchr(str, '@');
307     if(domain and point)
308       if(point > domain)
309         point = NULL;
310 
311     if(net) {
312       macro_addr(str, _ZONE, addr);
313       macro_addr(net+1, _NET, addr);
314       if(node)
315         macro_addr(node+1, _NODE, addr);  // zone:net/node
316       else
317         addr->node = mainaka->node;                // zone:net
318     }
319     else {
320       addr->zone = mainaka->zone;
321       if(node) {
322         if(*str != '/')
323           macro_addr(str, _NET, addr);      // net/node
324         else
325           addr->net = mainaka->net;                  // /node
326         macro_addr(node+1, _NODE, addr);
327       }
328       else {
329         if(point == str)
330           addr->node = mainaka->node;                // .point
331         else
332           macro_addr(str, _NODE, addr);     // node.point
333         addr->net = mainaka->net;
334       }
335     }
336     if(point)
337       macro_addr(point+1, _POINT, addr);
338   }
339   if(domain == NULL)
340     domain = str+strlen(str);   // point at NUL char
341 
342   return(domain);
343 }
344 
345 
346 //  ------------------------------------------------------------------
347 
make_addr_str(char * str,Addr * addr,char * domain)348 static char* make_addr_str(char* str, Addr* addr, char* domain) {
349 
350   char* ptr = str;
351   static char buf[20];
352 
353   *ptr = NUL;
354 
355   if(addr->zone) {
356     if(addr->zone == GFTN_ALL)
357       ptr = stpcpy(ptr, "*");
358     else {
359       sprintf(buf, "%u", addr->zone);
360       ptr = stpcpy(ptr, buf);
361     }
362     *ptr++ = ':';
363   }
364 
365   if(addr->net == GFTN_ALL)
366     ptr = stpcpy(ptr, "*");
367   else {
368     sprintf(buf, "%u", addr->net);
369     ptr = stpcpy(ptr, buf);
370   }
371   *ptr++ = '/';
372 
373   if(addr->node == GFTN_ALL)
374     ptr = stpcpy(ptr, "*");
375   else {
376     sprintf(buf, "%u", addr->node);
377     ptr = stpcpy(ptr, buf);
378   }
379 
380   if(addr->point) {
381     *ptr++ = '.';
382     if(addr->point == GFTN_ALL)
383       ptr = stpcpy(ptr, "*");
384     else {
385       sprintf(buf, "%u", addr->point);
386       ptr = stpcpy(ptr, buf);
387     }
388   }
389 
390   if(domain and *domain) {
391     *ptr++ = '@';
392     ptr = stpcpy(ptr, domain);
393   }
394 
395   *ptr = NUL;
396 
397   return(str);
398 }
399 
400 
401 //  ------------------------------------------------------------------
402 //  Compare two nodes by name/address/file/pos
403 
cmp_nnlsts(const _GEIdx & A,const _GEIdx & B)404 static bool cmp_nnlsts(const _GEIdx &A, const _GEIdx &B) {
405 
406   int cmp;
407 
408   if((cmp = stricmp(A.name, B.name)) != 0)
409     return(cmp < 0);
410   if((cmp = CmpV(A.addr.zone, B.addr.zone)) != 0)
411     return(cmp < 0);
412   if((cmp = CmpV(A.addr.net, B.addr.net)) != 0)
413     return(cmp < 0);
414   if((cmp = CmpV(A.addr.node, B.addr.node)) != 0)
415     return(cmp < 0);
416   if((cmp = CmpV(A.addr.point, B.addr.point)) != 0)
417     return(cmp < 0);
418   if((cmp = CmpV(A.pos, B.pos)) != 0)
419     return(cmp < 0);
420   return false;
421 }
422 
423 
424 //  ------------------------------------------------------------------
425 //  Compare two nodes by address/name/file/pos
426 
cmp_anlsts(const _GEIdx & A,const _GEIdx & B)427 static bool cmp_anlsts(const _GEIdx &A, const _GEIdx &B) {
428 
429   int cmp;
430 
431   if((cmp = CmpV(A.addr.zone, B.addr.zone)) != 0)
432     return(cmp < 0);
433   if((cmp = CmpV(A.addr.net, B.addr.net)) != 0)
434     return(cmp < 0);
435   if((cmp = CmpV(A.addr.node, B.addr.node)) != 0)
436     return(cmp < 0);
437   if((cmp = CmpV(A.addr.point, B.addr.point)) != 0)
438     return(cmp < 0);
439   if((cmp = stricmp(A.name, B.name)) != 0)
440     return(cmp < 0);
441   if((cmp = CmpV(A.pos, B.pos)) != 0)
442     return(cmp < 0);
443   return false;
444 }
445 
446 
447 //  ------------------------------------------------------------------
448 #if defined(_MSC_VER)
449 enum{ sort_by_address=0, sort_by_name } static sort_type;
operator <(const _GEIdx & A,const _GEIdx & B)450 bool operator<(const _GEIdx &A, const _GEIdx &B)
451 {
452   if (sort_type==sort_by_address)
453     return cmp_anlsts(A, B);
454   else
455     return cmp_nnlsts(A, B);
456 }
457 #endif
458 //  ------------------------------------------------------------------
459 
CvtName(char * inp)460 static char* CvtName(char* inp) {
461 
462   char buf[300];
463   char* p;
464   char* q;
465 
466   // Convert underlines to spaces
467 
468   p = inp;
469   while(*p)
470     if(*(p++) == '_')
471       *(p-1) = ' ';
472 
473   // Strip leading spaces
474 
475   p = inp;
476   while(isspace(*p))
477     p++;
478   q = &inp[strlen(p)-1];
479 
480   // Strip trailing spaces
481 
482   while(isspace(*q))
483     *q-- = NUL;
484 
485   // Search for last space or point
486 
487   while(*q != ' ' and *q != '.' and q > p)
488     q--;
489 
490   // If last char is a point, find last space instead
491 
492   if(*(q+1) == 0)
493     while(*q != ' ' and q > p)
494       q--;
495 
496   // Exchange last name and first name(s)
497 
498   if(p != q) {
499     strcpy(stpcpy(buf, q+1), ", ");
500     *(q+(*q == '.' ? 1 : 0)) = 0;
501     strcat(buf, p);
502     strcpy(inp, buf);
503   }
504   struplow(inp);
505   return inp;
506 }
507 
508 
509 //  ------------------------------------------------------------------
510 
511 #ifdef GOLDNODE_STATS
calc_statistic(std::ofstream & ofp,int * observation,float N)512 void calc_statistic(std::ofstream &ofp, int* observation, float N) {
513 
514   int i;
515   float mean = 0.0;
516   float sumfrekvens = 0.0;
517   float varians = 0.0;
518 
519   //         12   12345   12345   123456   123456789012
520   ofp << ".---------------------------------------------." << std::endl
521       << "|   x |  h(x) |  f(x) | x*f(x) | (x-m)^2*f(x) |" << std::endl
522       << "|-----+-------+-------+--------+--------------|" << std::endl;
523 
524   for(i=0; i<100; i++) {
525     float x = i;
526     if(observation[i]) {
527       float hyppighed = observation[i];
528       float frekvens = hyppighed / N;
529       mean += x * frekvens;
530       sumfrekvens += frekvens;
531     }
532   }
533 
534   for(i=0; i<100; i++) {
535     float x = i;
536     if(observation[i]) {
537       float hyppighed = observation[i];
538       float frekvens = hyppighed / N;
539       float vartmp =  (x-mean)*(x-mean)*frekvens;
540       varians += vartmp;
541       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;
542     }
543   }
544 
545   ofp << "|-----+-------+-------+--------+--------------|" << std::endl
546       << "| 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
547       << "`---------------------------------------------'" << std::endl
548       << std::endl
549       << "Mean: " << std::setprecision(1) << mean << std::endl
550       << "Variance = " << varians << std::endl
551       << "Standard deviation = " << sqrt(varians) << std::endl
552       << std::endl;
553 }
554 #endif
555 
556 
557 //  ------------------------------------------------------------------
558 //  some useful string operations
559 
index_line(char * p,char * ptrs[5])560 inline void index_line(char* p, char* ptrs[5]) {
561 
562   for(int i=0; i<5; i++) {
563     char* q = p;
564     while(*q != ',' and *q) {
565       if(*q == '_')
566         *q = ' ';
567       q++;
568     }
569     if(*q) {
570       ptrs[i] = p;
571       *q++ = NUL;
572       p = q;
573     }
574   }
575 }
576 
577 
578 //  ------------------------------------------------------------------
579 //  Read the nodelists and userlists
580 
read_nodelists()581 static void read_nodelists()
582 {
583   gfile lfp;
584   long pos;
585   char* ptr;
586   _GEIdx nlst;
587   Addr nlstz;
588   char buf[512], buf2[100];
589   int point;
590   uint line, realfno;
591   size_t no, nodes;
592   const char* name;
593   char* lp[5];
594   geidxlist nodeidx;
595   stamp_iter fno;
596   addr_iter zno;
597 
598   nodes = 0;
599 
600   if(not quiet) std::cout << std::endl << "* Compiling nodelists:" << std::endl;
601 
602   // Delete the current indexfiles so they don't take up space
603   remove(addrindex.c_str());
604   remove(nodeindex.c_str());
605 
606   // Compile nodelists
607   for(realfno=0, fno=nodelist.begin(), zno=nodezone.begin(); fno != nodelist.end(); fno++, zno++) {
608 
609     if (nodes < maxnodes)
610     {
611       lfp.Fopen(fno->fn, "rb", sh_mod);
612       if (lfp.isopen())
613       {
614         lfp.SetvBuf(NULL, _IOFBF, 32000);
615         fno->ft = GetFiletime(fno->fn);
616 
617         // Initialize for each nodelist file
618         no = 0;
619         pos = 0;
620         line = 0;
621         point = YES;
622         nlst.reset();
623         nlstz = nlst.addr = *zno;
624         name = CleanFilename(fno->fn);
625 
626         // Read all nodes
627         while (lfp.Fgets(buf, sizeof(buf)))
628         {
629           line++;
630 
631           // Break out if eof-marker is found
632           if(*buf == '\x1A')
633             break;
634 
635           // Note file position
636           nlst.pos = pos;
637 
638           // Get line length and fix possible errors
639           uint llen = strlen(buf);
640           ptr = buf+llen-1;
641           while(llen and not (*ptr == '\r' or *ptr == '\n' or *ptr == '\x1A')) {
642             buf[llen] = ' ';
643             if(not quiet) {
644               int len = 16-strlen(name);
645               std::cout << "\r* |--" << name << std::setw((len > 0) ? len : 1) << " " << "Warning line " << line << " - Invalid NUL char encountered." << std::endl;
646             }
647             llen = strlen(buf);
648             ptr = buf+llen-1;
649           }
650           pos += llen;
651 
652           // Skip whitespace
653           ptr = buf;
654           while(isspace(*ptr))
655             ptr++;
656 
657           if(*ptr != ';' and *ptr) {
658 
659             // First test for FD pvt extension
660             if(toupper(*ptr) == 'B') {   // Boss
661               nlst.addr.reset();
662               parse_address(ptr+5, &nlst.addr, &nlstz);
663               point = YES;
664               continue;
665             }
666 
667             // Test for Goldware extension
668             if(isdigit(*ptr)) {
669               nlst.addr.reset();
670               parse_address(ptr+5, &nlst.addr, &nlstz);
671               point = YES;
672             }
673 
674             // Hold,32,TriCom,Hornbaek,Lars_Joergensen,45-12345678,2400,XX
675 
676             // Form the full node address
677             index_line(ptr, lp);
678 
679             // NOTE: I use the fact that the third letter in lp[0] is unique
680             //       for all valid attrs to speed up processing
681 
682             switch(*lp[0] ? toupper(lp[0][2]) : 0) {
683               case 'N':   // zone
684                 nlst.addr.zone = nlst.addr.net = atow(lp[1]);
685                 nlst.addr.node = nlst.addr.point = 0;
686                 point = NO;
687                 break;
688 
689               case 'G':   // Region
690                 nlst.addr.net = atow(lp[1]);
691                 nlst.addr.node = nlst.addr.point = 0;
692                 point = NO;
693                 if(nlst.addr.net >= 10000)
694                   continue;
695                 break;
696 
697               case 'S':   // Host
698                 {
699                   nlst.addr.net = atow(lp[1]);
700                   nlst.addr.node = nlst.addr.point = 0;
701                   point = NO;
702                   Addr a;
703                   fast_parse_addr(lp[2],&a);
704                   if(a.net) {                   // Is POINTS24 format ?
705                     nlst.addr.net = a.net;
706                     nlst.addr.node = a.node;
707                     nlst.addr.point = 0;
708                     point = YES;
709                   }
710                 }
711                 break;
712 
713               case 'B':   // Hub
714                 nlst.addr.node = atow(lp[1]);
715                 nlst.addr.point = 0;
716                 point = NO;
717                 break;
718 
719               case 'I':   // point
720                 nlst.addr.point = atow(lp[1]);
721                 break;
722 
723               case 'T':   // Pvt
724               case 'W':   // Down
725               case 'L':   // Hold
726               default:
727                 if(point)
728                   nlst.addr.point = atow(lp[1]);
729                 else {
730                   nlst.addr.node = atow(lp[1]);
731                   nlst.addr.point = 0;
732                 }
733                 break;
734             }
735 
736             if(ISTWIRLY(no)) {
737               int len = 16-strlen(name);
738               std::cout << "\r* \\--" << name << std::setw((len > 0) ? len : 1) << " " << "Zone " << nlst.addr.zone << "   \tNet " << nlst.addr.net << "   \tNodes " << (uint32_t)no << "        " << std::flush;
739             }
740 
741             bool include = true;
742 
743             // Check address against the exclude masks
744             for(addr_iter n=excludenode.begin(); n != excludenode.end(); n++) {
745               if(match_addr_mask(&(*n), &nlst.addr)) {
746                 include = false;
747                 break;
748               }
749             }
750 
751             // Check address against the include masks
752             if(not include) {
753               for(addr_iter n=includenode.begin(); n != includenode.end(); n++) {
754                 if(match_addr_mask(&(*n), &nlst.addr)) {
755                   include = true;
756                   break;
757                 }
758               }
759             }
760 
761             if(include) {   // Address was okay
762 
763               // Convert name to Goldware standard
764               strxcpy(nlst.name, CvtName(lp[4]), sizeof(nlst.name));
765 
766               // Prepare the rest
767               nlst.pos |= ((((dword)realfno) << 24) & 0xFF000000L);
768 
769               // Append to end of list
770               nodeidx.push_back(nlst);
771               ++nodes;
772 
773               // Count the node
774               no++;
775 
776               // Stop if limit is reached
777               if(nodes >= maxnodes)
778                 break;
779             }
780           }
781         }
782 
783         if(not quiet) {
784           int len = 16-strlen(name);
785           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;
786         }
787 
788         lfp.Fclose();
789         ++realfno;
790       }
791       else {
792         if(not quiet) std::cout << "Error opening nodelist " << fno->fn << '!' << std::endl;
793         *(fno->fn) = NUL;
794       }
795     }
796   }
797 
798   // Compile userlists
799   if(userlist.size()) {
800     if(not quiet) std::cout << std::endl << "* Compiling userlists:" << std::endl;
801   }
802 
803   pos = 0;
804 
805   for(fno=userlist.begin(), zno=userzone.begin(); fno != userlist.end() and nodes < maxnodes; fno++, zno++) {
806 
807     no = 0;
808 
809     lfp.Fopen(fno->fn, "rt", sh_mod);
810     if (lfp.isopen())
811     {
812       lfp.SetvBuf(NULL, _IOFBF, 32000);
813 
814       name = CleanFilename(fno->fn);
815 
816       if (nodes < maxnodes)
817       {
818         while (lfp.Fgets(buf, sizeof(buf)))
819         {
820           // Get node data
821           strbtrim(buf);
822           ptr = buf + strlen(buf) - 1;
823           while(*ptr != ' ')
824             ptr--;
825           nlst.reset();
826           nlst.addr = *zno;
827           fast_parse_addr(ptr+1, &nlst.addr);
828           *ptr = NUL;
829           strbtrim(buf);
830 
831           // Convert "lastname, firstname" to "firstname lastname"
832           ptr = strchr(buf, ',');
833           if(ptr) {
834             *ptr++ = NUL;
835             strxmerge(buf2, 100, strskip_wht(ptr), " ", buf, NULL);
836             ptr = buf2;
837           }
838           else {
839             ptr = buf;
840           }
841 
842           // Convert name to Goldware standard
843           strxcpy(nlst.name, CvtName(ptr), sizeof(nlst.name));
844 
845           bool include = true;
846 
847           // Check address against the exclude masks
848           for(addr_iter n=excludenode.begin(); n != excludenode.end(); n++) {
849             if(match_addr_mask(&(*n), &nlst.addr)) {
850               include = false;
851               break;
852             }
853           }
854 
855           // Check address against the include masks
856           if(not include) {
857             for(addr_iter n=includenode.begin(); n != includenode.end(); n++) {
858               if(match_addr_mask(&(*n), &nlst.addr)) {
859                 include = true;
860                 break;
861               }
862             }
863           }
864 
865           if(include) {   // Address was okay
866 
867             if(ISTWIRLY(nodes)) {
868               int len = 16-strlen(name);
869               std::cout << "\r* \\--" << name << std::setw((len > 0) ? len : 1) << " " << "Nodes: " << (uint32_t)nodes << "        " << std::flush;
870             }
871 
872             // Indicate userlist
873             nlst.pos = (long)0xFF000000L | (pos++);
874 
875             // Append to end of list
876             nodeidx.push_back(nlst);
877             ++nodes;
878 
879             // Count the node
880             no++;
881 
882             // Stop if limit is reached
883             if(nodes >= maxnodes)
884               break;
885           }
886         }
887       }
888 
889       if(not quiet) {
890         int len = 16-strlen(name);
891         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;
892       }
893 
894       lfp.Fclose();
895     }
896     else {
897       if(not quiet) std::cout << "Error opening userlist " << fno->fn << '!' << std::endl;
898     }
899   }
900 
901   #ifdef GOLDNODE_STATS
902   if(make_stats) {
903 
904     if(not quiet) std::cout << "* Writing statistics to " << statfilename << NL;
905 
906     std::ofstream ofp(statfilename);
907     if(not ofp) {
908       if(not quiet) std::cout << "Error opening statfile " << statfilename << '!' << NL;
909     }
910     else {
911       ofp << "Nodename size statistics:" << std::endl;
912       calc_statistic(ofp, statistic.nodename, nodes);
913 
914       ofp << std::endl << "Location size statistics:" << std::endl;
915       calc_statistic(ofp, statistic.location, nodes);
916 
917       ofp << std::endl << "Sysopname size statistics:" << std::endl;
918       calc_statistic(ofp, statistic.sysopname, nodes);
919     }
920   }
921   else {
922   #endif
923     // At last, sort the nodes
924     geidxlist::iterator curr, prev;
925     std::map<long, dword> namepos;
926 
927     // Sort by name
928     if(not quiet) std::cout << NL << "* Sorting by name " << std::flush;
929 #if defined(_MSC_VER)
930     sort_type = sort_by_name;
931     nodeidx.sort();
932 #else
933     nodeidx.sort(cmp_nnlsts);
934 #endif
935     // Write the name-sorted .GXN
936     gfile fp(nodeindex.c_str(), "wb", sh_mod);
937     if (fp.isopen())
938     {
939       name = CleanFilename(nodeindex.c_str());
940 
941       gfile fido;
942       if (fidouser) fido.Fopen(fidouserlst, "wt", sh_mod);
943 
944       if (!fido.isopen())
945       {
946         if(not quiet) std::cout << "\b, writing " << name << ' ' << std::flush;
947         fidouser = false;
948       }
949       else {
950         if(not quiet) std::cout << "\b, writing " << name << " and " << fidouserlst << ' ' << std::flush;
951       }
952 
953       int nn = 0;
954       dword nodenum = 0;
955       for(prev = nodeidx.end(), curr = nodeidx.begin(); curr != nodeidx.end(); prev = curr++) {
956 
957         if(ISTWIRLY(nn++))
958           twirly();
959 
960         if(ignoredups) {
961           if(prev != nodeidx.end() && match_addr_mask(&curr->addr, &prev->addr)) {
962             if(strieql(curr->name, prev->name)) {
963               #ifdef DEBUG
964               if(not quiet) std::cout << "* Dupe: " << curr->addr.zone << ':' << curr->addr.net << '/' << curr->addr.node << '.' << curr->addr.point << ' ' << curr->name << NL;
965               #endif
966               nodeidx.erase(curr);
967               curr = prev;
968               ++dups;
969               continue;
970             }
971           }
972           fp.Fwrite(&(*curr), sizeof(_GEIdx));
973         }
974         else
975           fp.Fwrite(&(*curr), sizeof(_GEIdx));
976 
977         namepos[curr->pos] = nodenum++;
978         if (fidouser)
979         {
980           char buf[256];
981           fido.Printf("%-36.36s%24.24s\n", curr->name, make_addr_str(buf, &curr->addr, ""));
982         }
983       }
984 
985       fp.Fclose();
986     }
987 
988     // Sort by address
989     if(not quiet) std::cout << ' ' << NL "* Sorting by node " << std::flush;
990 #if defined(_MSC_VER)
991     sort_type = sort_by_address;
992     nodeidx.sort();
993 #else
994     nodeidx.sort(cmp_anlsts);
995 #endif
996 
997     // Write the address-sorted .GXA
998     fp.Fopen(addrindex.c_str(), "wb", sh_mod);
999     if (fp.isopen())
1000     {
1001       name = CleanFilename(addrindex.c_str());
1002       if(not quiet) std::cout << "\b, writing " << name << ' ' << std::flush;
1003       int nn = 0;
1004       for(curr = nodeidx.begin(); curr != nodeidx.end(); curr++) {
1005         if(ISTWIRLY(nn++))
1006           twirly();
1007         fp.Fwrite(&namepos[curr->pos], sizeof(dword));
1008       }
1009       fp.Fclose();
1010     }
1011 
1012     // Write the list index in .GXL
1013     fp.Fopen(listindex.c_str(), "wt", sh_mod);
1014     if (fp.isopen())
1015     {
1016       name = CleanFilename(listindex.c_str());
1017       if (not quiet) std::cout << ' ' << NL "* Writing " << name << std::endl;
1018       for (fno=nodelist.begin(); fno != nodelist.end(); fno++)
1019       {
1020         if (*(fno->fn))
1021           fp.Printf("%s %u\n", fno->fn, fno->ft);
1022       }
1023 
1024       fp.Fclose();
1025     }
1026 
1027     // Note compile time
1028     runtime = gtime(NULL) - runtime;
1029 
1030     if(not quiet) {
1031       if(dups) {
1032         std::cout << NL "* Total duplicate nodes: " << (uint32_t)dups << '.' << NL;
1033       }
1034       std::cout << NL "* Nodelist compile completed. Compile time: " << (uint32_t)(runtime/60) << " min, " << (uint32_t)(runtime%60) << " sec." << NL;
1035     }
1036   #ifdef GOLDNODE_STATS
1037   }
1038   #endif
1039 }
1040 
1041 
1042 //  ------------------------------------------------------------------
1043 
check_nodelists(bool force)1044 static void check_nodelists(bool force)
1045 {
1046   uint n;
1047   int compilen, compileu;
1048   static Path buf, newpath;
1049 
1050   // Find newest nodelists
1051   for(n=0,compilen=0; n<nodelist.size(); n++) {
1052 
1053     strcpy(buf, CleanFilename(nodelist[n].fn));
1054     char *ext = strchr(buf, '.');
1055     if(ext and ((atoi(ext+1) == 999) or (ext[1] == '*'))) {
1056       extractdirname(newpath, nodelist[n].fn);
1057       int extpos = ext-buf+1;
1058       strcpy(ext, ".*");
1059       gposixdir f(newpath);
1060       const gdirentry *de;
1061       time32_t listtime = 0;
1062       bool listdefined = false;
1063       while((de = f.nextentry(buf)) != NULL)
1064         if(atoi(de->name.c_str()+extpos)) {
1065           if(not listdefined or (de->stat_info.st_mtime-listtime > 0)) {
1066             listtime = de->stat_info.st_mtime;
1067             listdefined = true;
1068             strxmerge(nodelist[n].fn, sizeof(Path), newpath, de->name.c_str(), NULL);
1069           }
1070         }
1071       strchg(nodelist[n].fn, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
1072     }
1073   }
1074 
1075   // Get timestamps from .GXL file
1076   gfile fp(listindex.c_str(), "rt", sh_mod);
1077   if (fp.isopen())
1078   {
1079     while (fp.Fgets(buf, sizeof(buf)))
1080     {
1081       char* key;
1082       char* val=buf;
1083       getkeyval(&key, &val);
1084       key = strxcpy(newpath, strbtrim(key), sizeof(Path));
1085       _MapPath(key);
1086       strchg(key, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
1087       for(n=0; n<nodelist.size(); n++) {
1088         if(strieql(nodelist[n].fn, key)) {
1089           nodelist[n].ft = atol(val);
1090           break;
1091         }
1092       }
1093       for(n=0; n<userlist.size(); n++) {
1094         if(strieql(userlist[n].fn, key)) {
1095           userlist[n].ft = atol(val);
1096           break;
1097         }
1098       }
1099     }
1100     fp.Fclose();
1101   } else
1102     perror("error opening .gxl file");
1103 
1104   // Check nodelists
1105   for(n=0,compilen=0; n<nodelist.size(); n++) {
1106     if(abs(long(GetFiletime(nodelist[n].fn) - nodelist[n].ft)) > 1) {
1107       nodelist[n].fc = YES;
1108       compilen++;
1109     }
1110   }
1111 
1112   if(not quiet) {
1113     if(compilen) {
1114       std::cout << "* " << compilen << " new nodelist file" << ((compilen == 1) ? "" : "s") << " found." NL;
1115     }
1116     else if(nodelist.size()) {
1117       std::cout << "* The nodelist file" << ((nodelist.size() == 1) ? " is" : "s are") << " up-to-date." NL;
1118     }
1119   }
1120 
1121   // Check userlists
1122   for(n=0,compileu=0; n<userlist.size(); n++) {
1123     if(abs(long(GetFiletime(newpath) - userlist[n].ft)) > 1) {
1124       userlist[n].fc = YES;
1125       compileu++;
1126     }
1127   }
1128 
1129   if(not quiet) {
1130     if(compileu) {
1131       std::cout << "* " << compileu << " new userlist file" << ((compileu == 1) ? "" : "s") << " found." NL;
1132     }
1133     else if(userlist.size()) {
1134       std::cout << "* The userlist file" << ((userlist.size() == 1) ? " is" : "s are") << " up-to-date." NL;
1135     }
1136   }
1137 
1138   if(force or compilen or compileu)
1139     read_nodelists();
1140 }
1141 
1142 
1143 //  ------------------------------------------------------------------
1144 
fatal_error(const char * what)1145 static void fatal_error(const char* what) {
1146 
1147   if(not quiet) std::cout << what << NL;
1148   exit(5);
1149 }
1150 
1151 
1152 //  ------------------------------------------------------------------
1153 
do_if(char * val)1154 static int do_if(char* val) {
1155 
1156   if(strieql(val, "OS/2") or strieql(val, "OS2")) {
1157     #ifdef __OS2__
1158     return true;
1159     #else
1160     return false;
1161     #endif
1162   }
1163   else if(strieql(val, "NT") or strieql(val, "W32") or strieql(val, "WIN32")) {
1164     #ifdef __WIN32__
1165     return true;
1166     #else
1167     return false;
1168     #endif
1169   }
1170   else if(strieql(val, "386") or strieql(val, "DOS") or strieql(val, "DPMI32")) {
1171     #ifdef __MSDOS__
1172     return true;
1173     #else
1174     return false;
1175     #endif
1176   }
1177   else if(strieql(val, "LINUX") or strieql(val, "UNIX")) {
1178     #ifdef __UNIX__
1179     return true;
1180     #else
1181     return false;
1182     #endif
1183   }
1184   else if (strieql(val, "SPELL"))
1185   {
1186     #ifdef GCFG_SPELL_INCLUDED
1187     return true;
1188     #else
1189     return false;
1190     #endif
1191   }
1192   else if(strieql(val, "FIREBIRD"))
1193     return true;
1194   else if(strieql(val, "ASA") or strieql(val, "PLUS"))
1195     return true;
1196   else if(strieql(val, "YES") or strieql(val, "TRUE") or strieql(val, "ON"))
1197     return true;
1198   return !!atoi(val);
1199 }
1200 
1201 
1202 //  ------------------------------------------------------------------
1203 
_MapPath(char * fmap,bool reverse)1204 char* _MapPath(char* fmap, bool reverse) {
1205 
1206   Path buf, cmap;
1207 
1208   strxcpy(cmap, fmap, sizeof(Path));
1209   if(reverse)
1210     strchg(cmap, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
1211 
1212   std::vector< std::pair<std::string, std::string> >::iterator i;
1213   for(i = mappath.begin(); i != mappath.end(); i++) {
1214     const char* p = reverse ? i->second.c_str() : i->first.c_str();
1215     const char* q = reverse ? i->first.c_str() : i->second.c_str();
1216     if(strnieql(cmap, p, strlen(p))) {
1217       strxcpy(buf, fmap, sizeof(Path));
1218       strxmerge(fmap, sizeof(Path), q, buf+strlen(p), NULL);
1219       char sl1, sl2;
1220       const char* ptr;
1221 
1222       ptr = strpbrk(p, "/\\");
1223       sl1 = ptr ? *ptr : NUL;
1224       ptr = strpbrk(q, "/\\");
1225       sl2 = ptr ? *ptr : NUL;
1226 
1227       if(sl1 and sl2 and (sl1 != sl2))
1228         strchg(fmap, sl1, sl2);
1229 
1230       break;
1231     }
1232   }
1233   return fmap;
1234 }
1235 
1236 
1237 //  ------------------------------------------------------------------
1238 
parse_config(const char * __configfile,Addr & zoneaddr)1239 static int parse_config(const char *__configfile, Addr& zoneaddr)
1240 {
1241   char buf[512];
1242   const char * const top_buf = buf+sizeof(buf);
1243   char* ptr;
1244   char* key;
1245   word crc;
1246   char* value;
1247   char* value2;
1248   int _gotcond,line = 0;
1249   static int in_if = NO;
1250   static int in_else = NO;
1251   static int cond_status = YES;
1252 
1253   gfile fp(__configfile, "rt", sh_mod);
1254   if (fp.isopen())
1255   {
1256     while (fp.Fgets((ptr=buf), sizeof(buf)))
1257     {
1258       line++;
1259       // Replace TABs with SPACEs
1260       ptr = strskip_wht(ptr);
1261       if(*ptr != ';' and *ptr) {
1262         crc=getkeyvalcrc(&key, &ptr);
1263         getkeyval(&value, &ptr);
1264         getkeyval(&value2, &ptr);
1265 
1266         _gotcond = YES;
1267         switch(crc) {
1268           case CRC_IF:
1269             if(in_if) {
1270               if(not quiet) std::cout << "* " << __configfile << ": Misplaced IF at line " << line << ". IF's cannot be nested." << NL;
1271             }
1272             in_if = YES;
1273             cond_status = do_if(value);
1274             break;
1275           case CRC_ELIF:
1276           case CRC_ELSEIF:
1277             if((not in_if) or in_else) {
1278               if(not quiet) std::cout << "* " << __configfile << ": Misplaced ELIF/ELSEIF at line " << line <<  '.' << NL;
1279             }
1280             cond_status = do_if(value);
1281             break;
1282           case CRC_ELSE:
1283             if((not in_if) or in_else) {
1284               if(not quiet) std::cout << "* " << __configfile << "Misplaced ELSE at line " << line <<  '.' << NL;
1285             }
1286             in_else = YES;
1287             cond_status ^= YES;
1288             break;
1289           case CRC_ENDIF:
1290             if(not in_if) {
1291               if(not quiet) std::cout << "* " << __configfile << ": Misplaced ENDIF at line " << line << '.' << NL;
1292             }
1293             in_if = in_else = NO;
1294             cond_status = YES;
1295             break;
1296           default:
1297             _gotcond = NO;
1298             break;
1299         }
1300 
1301         if((not _gotcond) and cond_status) {
1302           switch(crc) {
1303             case CRC_NODEPATH:
1304               _MapPath(value);
1305               PathCopy(nodepath, value);
1306               break;
1307             case CRC_ADDRESS:
1308             case CRC_AKA:
1309               if(not zoneaddr.net) {
1310                 parse_address(value, &zoneaddr, &zoneaddr);
1311                 zoneaddr.point = 0;
1312               }
1313               break;
1314             case CRC_NODELIST:
1315               {
1316                 Stamp ndl;
1317                 Addr ndz;
1318 
1319                 if(atoi(value2)) {
1320                   parse_address(value2, &ndz, &ndz);
1321                   if(ndz.zone == 0) {
1322                     ndz.zone  = ndz.node;
1323                     ndz.net   = 0;
1324                     ndz.node  = 0;
1325                   }
1326                 }
1327                 else
1328                   ndz = zoneaddr;
1329                 ndz.point = 0;
1330                 ndl.ft = (dword)-1;
1331                 ndl.fc = NO;
1332                 strschg_environ(value, top_buf-value);
1333                 _MapPath(value);
1334                 strcpy(ndl.fn, value);
1335                 nodelist.push_back(ndl);
1336                 nodezone.push_back(ndz);
1337               }
1338               break;
1339             case CRC_USERLIST:
1340               {
1341                 Stamp ndl;
1342                 Addr ndz;
1343 
1344                 if(atoi(value2)) {
1345                   parse_address(value2, &ndz, &ndz);
1346                   if(ndz.zone == 0) {
1347                     ndz.zone  = ndz.node;
1348                     ndz.net   = 0;
1349                     ndz.node  = 0;
1350                   }
1351                 }
1352                 else
1353                   ndz = zoneaddr;
1354                 ndz.point = 0;
1355                 ndl.ft = (dword)-1;
1356                 ndl.fc = NO;
1357                 strschg_environ(value, top_buf-value);
1358                 _MapPath(value);
1359                 strcpy(ndl.fn, value);
1360                 userlist.push_back(ndl);
1361                 userzone.push_back(ndz);
1362               }
1363               break;
1364             case CRC_EXCLUDENODES:
1365               {
1366                 Addr exn;
1367                 parse_address(value, &exn, &zoneaddr);
1368                 excludenode.push_back(exn);
1369               }
1370               break;
1371             case CRC_INCLUDENODES:
1372               {
1373                 Addr inn;
1374                 parse_address(value, &inn, &zoneaddr);
1375                 includenode.push_back(inn);
1376               }
1377               break;
1378             case CRC_SHAREMODE:
1379               if(atoi(value))
1380                 sh_mod = atoi(value);
1381               else
1382                 sh_mod = GetYesno(value) ? SH_DENYNO : SH_COMPAT;
1383               break;
1384             case CRC_INCLUDE:
1385               strschg_environ(value, top_buf-value);
1386               _MapPath(value);
1387               if(not parse_config(value,zoneaddr))     // NOTE! This is a recursive call!
1388                 if(not quiet) std::cout << "* Could not read configuration file " << value << '!' << NL;
1389               break;
1390             case CRC_MAPPATH:
1391               {
1392                 std::pair<std::string, std::string> mapentry;
1393 
1394                 mapentry.first = value;
1395                 mapentry.second = value2;
1396                 mappath.push_back(mapentry);
1397               }
1398               break;
1399             default:
1400               break;
1401           }
1402         }
1403       }
1404     }
1405 
1406     return(YES);
1407   }
1408   else {
1409     return(NO);
1410   }
1411 }
1412 
1413 
1414 //  ------------------------------------------------------------------
1415 
ExistCfg(char * path,char * file)1416 static bool ExistCfg(char* path, char* file) {
1417 
1418   bool found = fexist(AddPath(path, file));
1419   if(found)
1420     strcat(path, file);
1421   return found;
1422 }
1423 
1424 
1425 //  ------------------------------------------------------------------
1426 
FindCfg(char * path)1427 static bool FindCfg(char* path) {
1428 
1429   bool found = false;
1430 
1431   if(!is_dir(path)) {
1432     if(fexist(path))
1433       return true;
1434     else
1435       return false;
1436   }
1437   AddBackslash(path);
1438   #if defined(__OS2__)
1439   found = ExistCfg(path, "ged2.cfg");
1440   #elif defined(__WIN32__)
1441   found = ExistCfg(path, "gedw32.cfg");
1442   #endif
1443   if(not found)
1444     found = ExistCfg(path, "golded.cfg");
1445   return found;
1446 }
1447 
1448 
1449 //  ------------------------------------------------------------------
1450 
read_config(const char * cfg,const char * argv_0)1451 static bool read_config(const char *cfg, const char *argv_0) {
1452 
1453   Addr zoneaddr;
1454   Path buf;
1455 
1456   bool found = (*cfg != NUL);
1457   if(not found) {
1458     // Look for configfilename in the environment
1459     const char *ptr = getenv("GOLDNODE");
1460     #if defined(__OS2__)
1461     if(not(ptr and *ptr))
1462       ptr = getenv("GED2");
1463     #elif defined(__WIN32__)
1464     if(not(ptr and *ptr))
1465       ptr = getenv("GEDW32");
1466     #endif
1467     if(not(ptr and *ptr))
1468       ptr = getenv("GOLDED");
1469     if(not(ptr and *ptr))
1470       ptr = getenv("GED");
1471     if(ptr and *ptr) {
1472       strxcpy(buf, ptr, sizeof(buf));
1473       found = FindCfg(buf);
1474     }
1475 
1476     // Get it in current directory
1477     if(not found) {
1478       getcwd(buf, sizeof(buf));
1479       found = FindCfg(buf);
1480     }
1481 
1482     // Get it where the the .EXE file is
1483     if(not found) {
1484       extractdirname(buf, argv_0);
1485       found = FindCfg(buf);
1486 
1487       // If we still could not find config name...
1488       if(not found)
1489         strcat(buf, "golded.cfg");
1490     }
1491   }
1492   else
1493     strxcpy(buf, cfg, sizeof(Path));
1494 
1495   nodelist.clear();
1496   nodezone.clear();
1497   userlist.clear();
1498   userzone.clear();
1499   mappath.clear();
1500   if(not parse_config(buf, zoneaddr)) {
1501     errorlevel = 1;
1502     return false;
1503   }
1504 
1505   if(nodelist.empty() and userlist.empty() == 0)
1506     fatal_error("* Error: No NODELISTs or USERLISTs defined!");
1507 
1508   if(zoneaddr.net == 0)
1509     fatal_error("* Error: No ADDRESS or AKAs defined!");
1510 
1511   if(nodepath.empty())
1512     nodepath = getcwd(buf, sizeof(buf));
1513 
1514   AddBackslash(nodepath);
1515   MakePathname(listindex, nodepath, "goldnode.gxl");
1516   MakePathname(nodeindex, nodepath, "goldnode.gxn");
1517   MakePathname(addrindex, nodepath, "goldnode.gxa");
1518   size_t n;
1519   for(n=0; n<nodelist.size(); n++)
1520     MakePathname(nodelist[n].fn, nodepath.c_str(), nodelist[n].fn);
1521   for(n=0; n<userlist.size(); n++)
1522     MakePathname(userlist[n].fn, nodepath.c_str(), userlist[n].fn);
1523 
1524   return true;
1525 }
1526 
1527 
1528 //  ------------------------------------------------------------------
1529 
run_gn(int argc,char * argv[])1530 static void run_gn(int argc, char* argv[]) {
1531 
1532   int n;
1533   char* ptr;
1534   bool force=false, conditional=false;
1535 
1536   // Note start time
1537   runtime = time(NULL);
1538 
1539   const char *cfg = "";
1540 
1541   for(n=1; n<argc; n++) {
1542     if(strchr("-", *argv[n])) {
1543       ptr = argv[n]+2;
1544       if(*ptr == '=')
1545         ptr++;
1546       switch(toupper(argv[n][1])) {
1547 
1548         case 'C':
1549           conditional = true;
1550           break;
1551 
1552         case 'D':
1553           ignoredups = true;
1554           break;
1555 
1556         case 'F':
1557           force = true;
1558           break;
1559 
1560         case 'Q':
1561           quiet = true;
1562           break;
1563 
1564         #ifdef GOLDNODE_STATS
1565         case 'T':
1566           make_stats = true;
1567           break;
1568         #endif
1569 
1570         case 'U':
1571           fidouser = true;
1572           strcpy(fidouserlst, ptr);
1573           break;
1574 
1575       }
1576     }
1577     else
1578       cfg = argv[n];
1579   }
1580 
1581   if(not quiet) {
1582     std::cout << __gver_name__ << " - Nodelist Compiler for Golded+ v." << __gver_shortver__ << __gver_platform__ << __gver_postversion__ << "." NL
1583          << "Copyright (C) 1990-1999 Odinn Sorensen" NL
1584          << "Copyright (C) 1999-2001 Alexander S. Aganichev" NL
1585          << "Copyright (C) 2005 Stas Degteff & Golded+ team" NL
1586          << "-------------------------------------------------------------------------------\n" NL;
1587   }
1588 
1589   if(not(force or conditional)) {
1590     if(not quiet) {
1591       std::cout << "Commandline syntax: " << CleanFilename(argv[0]) << " [-options] [configfile]" NL
1592            << "\n[-options] =\t-C\t  Conditional compile." NL
1593            << "\t\t-F\t  Forced compile." NL
1594            << "\t\t-D\t  Remove duplicate nodes from index while compiling." NL
1595            << "\t\t-Q\t  Quiet compile. No screen output improves speed." NL
1596            << "\t\t-S<size>  Set max size of a name in the index." NL
1597            << "\t\t-U<file>  Create sorted FIDOUSER.LST userlist file." NL
1598       #ifdef GOLDNODE_STATS
1599            << "\t\t-T\t  Make statistics." NL
1600       #endif
1601            << "\n[configfile] =\t\t  The path AND filename of GOLDED.CFG" NL
1602            << "\t\t\t  configuration file to read.\n" NL;
1603     }
1604   }
1605   else {
1606 
1607     if(force)
1608       if(not quiet) std::cout << "* Forced compile." NL;
1609 
1610     if(read_config(cfg, argv[0])) {
1611       if(force or conditional)
1612         check_nodelists(force);
1613     }
1614     else {
1615       if(not quiet) std::cout << NL "Could not find the configuration file!" NL;
1616     }
1617   }
1618 }
1619 
1620 
1621 //  ------------------------------------------------------------------
1622 
main(int argc,char * argv[])1623 int main(int argc, char *argv[]) {
1624 
1625   throw_init();
1626 
1627   // set locale
1628   setlocale(LC_CTYPE, "");
1629   #if defined(GUTLOS_FUNCS)
1630   g_init_os(0);
1631   #endif
1632 
1633   #ifdef GOLDNODE_STATS
1634   memset(&statistic, 0, sizeof(nl_stat));
1635   #endif
1636 
1637   run_gn(argc, argv);
1638 
1639   #if defined(GUTLOS_FUNCS)
1640   g_deinit_os();
1641   #endif
1642 
1643   THROW_CHECK();
1644 
1645   return errorlevel;
1646 }
1647 
1648 
1649 //  ------------------------------------------------------------------
1650