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