see5-installer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rubocop.yml +11 -0
  4. data/CHANGELOG.md +5 -0
  5. data/Gemfile +10 -0
  6. data/README.md +29 -0
  7. data/Rakefile +12 -0
  8. data/ext/c5.0/Makefile +86 -0
  9. data/ext/c5.0/attwinnow.c +394 -0
  10. data/ext/c5.0/c50.c +330 -0
  11. data/ext/c5.0/classify.c +700 -0
  12. data/ext/c5.0/confmat.c +195 -0
  13. data/ext/c5.0/construct.c +853 -0
  14. data/ext/c5.0/contin.c +613 -0
  15. data/ext/c5.0/defns.i +788 -0
  16. data/ext/c5.0/discr.c +307 -0
  17. data/ext/c5.0/extern.i +170 -0
  18. data/ext/c5.0/formrules.c +720 -0
  19. data/ext/c5.0/formtree.c +1158 -0
  20. data/ext/c5.0/getdata.c +521 -0
  21. data/ext/c5.0/getnames.c +733 -0
  22. data/ext/c5.0/global.c +211 -0
  23. data/ext/c5.0/gpl.txt +674 -0
  24. data/ext/c5.0/implicitatt.c +1112 -0
  25. data/ext/c5.0/info.c +146 -0
  26. data/ext/c5.0/mcost.c +138 -0
  27. data/ext/c5.0/modelfiles.c +952 -0
  28. data/ext/c5.0/p-thresh.c +313 -0
  29. data/ext/c5.0/prune.c +1069 -0
  30. data/ext/c5.0/report.c +345 -0
  31. data/ext/c5.0/rules.c +579 -0
  32. data/ext/c5.0/ruletree.c +398 -0
  33. data/ext/c5.0/siftrules.c +1285 -0
  34. data/ext/c5.0/sort.c +156 -0
  35. data/ext/c5.0/subset.c +599 -0
  36. data/ext/c5.0/text.i +223 -0
  37. data/ext/c5.0/trees.c +740 -0
  38. data/ext/c5.0/update.c +129 -0
  39. data/ext/c5.0/utility.c +1146 -0
  40. data/ext/c5.0/xval +150 -0
  41. data/ext/c5.0/xval.c +402 -0
  42. data/ext/gritbot/Makefile +98 -0
  43. data/ext/gritbot/check.c +1110 -0
  44. data/ext/gritbot/cluster.c +342 -0
  45. data/ext/gritbot/common.c +1269 -0
  46. data/ext/gritbot/continatt.c +412 -0
  47. data/ext/gritbot/defns.i +623 -0
  48. data/ext/gritbot/discratt.c +459 -0
  49. data/ext/gritbot/extern.i +101 -0
  50. data/ext/gritbot/getdata.c +329 -0
  51. data/ext/gritbot/getnames.c +573 -0
  52. data/ext/gritbot/global.c +104 -0
  53. data/ext/gritbot/gpl.txt +674 -0
  54. data/ext/gritbot/gritbot.c +295 -0
  55. data/ext/gritbot/implicitatt.c +1108 -0
  56. data/ext/gritbot/inspect.c +794 -0
  57. data/ext/gritbot/modelfiles.c +687 -0
  58. data/ext/gritbot/outlier.c +415 -0
  59. data/ext/gritbot/sort.c +130 -0
  60. data/ext/gritbot/text.i +159 -0
  61. data/ext/gritbot/update.c +126 -0
  62. data/ext/gritbot/utility.c +1029 -0
  63. data/ext/see5-installer/extconf.rb +25 -0
  64. data/lib/see5/installer.rb +10 -0
  65. data/lib/see5/installer/version.rb +7 -0
  66. data/see5-installer.gemspec +30 -0
  67. metadata +115 -0
@@ -0,0 +1,687 @@
1
+ /*************************************************************************/
2
+ /* */
3
+ /* Copyright 2010 Rulequest Research Pty Ltd. */
4
+ /* */
5
+ /* This file is part of GritBot GPL Edition, a single-threaded version */
6
+ /* of GritBot release 2.01. */
7
+ /* */
8
+ /* GritBot GPL Edition is free software: you can redistribute it */
9
+ /* and/or modify it under the terms of the GNU General Public License */
10
+ /* as published by the Free Software Foundation, either version 3 of */
11
+ /* the License, or (at your option) any later version. */
12
+ /* */
13
+ /* GritBot GPL Edition is distributed in the hope that it will be */
14
+ /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
15
+ /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
16
+ /* GNU General Public License for more details. */
17
+ /* */
18
+ /* You should have received a copy of the GNU General Public License */
19
+ /* (gpl.txt) along with GritBot GPL Edition. If not, see */
20
+ /* */
21
+ /* <http://www.gnu.org/licenses/>. */
22
+ /* */
23
+ /*************************************************************************/
24
+
25
+
26
+
27
+ /*************************************************************************/
28
+ /* */
29
+ /* Routines for saving and reading sift files */
30
+ /* ------------------------------------------ */
31
+ /* */
32
+ /*************************************************************************/
33
+
34
+ /* Formats:
35
+
36
+ 1 <att> target att
37
+ 2 <att> use logs with att
38
+ 3 <att> <ltail> <htail> set low/high tail
39
+
40
+ 11 <lev> <att> <br> split on attribute value
41
+ 12 <lev> <att> <br> <cut> threshold test
42
+ 13 <lev> <att> <br> <subset> subset test
43
+
44
+ 21 <cov> <frac> <mode> [<val> <cf>]* 0 discrete cluster
45
+ 22 <cov> <mean> <sd> <lfrac> <llim> <hfrac> <hlim> low/high contin cluster
46
+
47
+ clusters may be followed by one or more caveats of the form
48
+ <att> <low> <high> or
49
+ <att> <subset>
50
+ */
51
+
52
+ #include "defns.i"
53
+ #include "extern.i"
54
+
55
+ int Entry;
56
+
57
+ char* Prop[]={"null",
58
+ "id",
59
+ "atts",
60
+ "att",
61
+ "sstat",
62
+ "elts",
63
+ "prec",
64
+ "label",
65
+ "def",
66
+ "minabnorm"
67
+ };
68
+
69
+ char PropName[20],
70
+ *PropVal=Nil,
71
+ *Unquoted;
72
+ int PropValSize=0;
73
+
74
+ #define PROPS 9
75
+
76
+ #define ERRORP 0
77
+ #define IDP 1
78
+ #define ATTSP 2
79
+ #define ATTP 3
80
+ #define SSTATP 4
81
+ #define ELTSP 5
82
+ #define PRECP 6
83
+ #define LABELP 7
84
+ #define DEFP 8
85
+ #define MINABNORMP 9
86
+
87
+
88
+ /*************************************************************************/
89
+ /* */
90
+ /* Check whether file is open. If it is not, open it and */
91
+ /* read/write header information and names */
92
+ /* */
93
+ /*************************************************************************/
94
+
95
+
96
+ void CheckFile(String Extension, Boolean Write)
97
+ /* --------- */
98
+ {
99
+ static char *LastExt="";
100
+
101
+ if ( ! Sf || strcmp(LastExt, Extension) )
102
+ {
103
+ LastExt = Extension;
104
+
105
+ if ( Sf )
106
+ {
107
+ fprintf(Sf, "\n");
108
+ fclose(Sf);
109
+ }
110
+
111
+ #ifdef INSPECT
112
+ ReadFilePrefix(Extension);
113
+ #else
114
+ if ( Write )
115
+ {
116
+ WriteFilePrefix(Extension);
117
+ }
118
+ else
119
+ {
120
+ ReadFilePrefix(Extension);
121
+ }
122
+ #endif
123
+ }
124
+ }
125
+ #ifndef INSPECT
126
+
127
+
128
+
129
+ /*************************************************************************/
130
+ /* */
131
+ /* Write information on system, parameters etc */
132
+ /* */
133
+ /*************************************************************************/
134
+
135
+
136
+ void WriteFilePrefix(String Extension)
137
+ /* --------------- */
138
+ {
139
+ time_t clock;
140
+ struct tm *now;
141
+
142
+ if ( ! (Sf = GetFile(Extension, "w")) )
143
+ {
144
+ Error(NOFILE, Fn, E_ForWrite);
145
+ }
146
+
147
+ clock = time(0);
148
+ now = localtime(&clock);
149
+ now->tm_mon++;
150
+ fprintf(Sf, "id=\"GritBot %s %d-%d%d-%d%d\"\n",
151
+ RELEASE,
152
+ now->tm_year + 1900,
153
+ now->tm_mon / 10, now->tm_mon % 10,
154
+ now->tm_mday / 10, now->tm_mday % 10);
155
+
156
+ SaveNames();
157
+
158
+ fprintf(Sf, "minabnorm=\"%g\"\n", MINABNORM);
159
+ }
160
+
161
+
162
+
163
+ void SaveCondition()
164
+ /* -------------- */
165
+ {
166
+ Attribute Att;
167
+ int CType, b, Bytes;
168
+ DiscrValue Br;
169
+ char SE[100];
170
+
171
+ if ( GEnv.Level < 0 ) return;
172
+
173
+ /* Save top condition */
174
+
175
+ Att = GEnv.Test[GEnv.Level].Att;
176
+ Br = GEnv.Test[GEnv.Level].Br;
177
+
178
+ /* Determine condition type */
179
+
180
+ CType = ( Br == 1 ? 11 :
181
+ Continuous(Att) || Ordered(Att) ? 12 :
182
+ Continuous(ClassAtt) && MaxAttVal[Att] > 3 ? 13 : 11 );
183
+
184
+ sprintf(SE, "%d %d %d %d", CType, GEnv.Level, Att, Br);
185
+ ExtendSiftEntry(SE);
186
+
187
+ /* Don't need to save anything else if this branch is 1 (N/A)
188
+ or if test is on two-valued discrete att */
189
+
190
+ if ( Br != 1 )
191
+ {
192
+ if ( Continuous(Att) || Ordered(Att) )
193
+ {
194
+ sprintf(SE, " %.8g", GEnv.Test[GEnv.Level].Cut);
195
+ ExtendSiftEntry(SE);
196
+ }
197
+ else
198
+ if ( Continuous(ClassAtt) && MaxAttVal[Att] > 3 )
199
+ {
200
+ /* Print subset of values */
201
+
202
+ Bytes = (MaxAttVal[Att]>>3) + 1;
203
+
204
+ ForEach(b, 0, Bytes-1)
205
+ {
206
+ sprintf(SE, " %x", GEnv.Test[GEnv.Level].Left[b]);
207
+ ExtendSiftEntry(SE);
208
+ }
209
+ }
210
+ }
211
+
212
+ ExtendSiftEntry("\n");
213
+ }
214
+
215
+
216
+
217
+ void SaveDiscrCluster(DiscrValue Expect, CaseCount Anoms, CaseCount Cases,
218
+ CaseCount *Freq)
219
+ /* ---------------- */
220
+ {
221
+ DiscrValue v;
222
+ float Xv;
223
+ char SE[100];
224
+
225
+ SaveCondition();
226
+
227
+ sprintf(SE, "21 %d %g %d",
228
+ Cases, (Cases - Anoms) / (Cases + 1E-3), Expect);
229
+ ExtendSiftEntry(SE);
230
+
231
+ ForEach(v, 1, MaxAttVal[ClassAtt])
232
+ {
233
+ if ( v == Expect ) continue;
234
+
235
+ Xv = XDScore(Freq[v], Cases, Anoms, Prior[ClassAtt][v]);
236
+
237
+ if ( Xv <= 1.0 / (MINABNORM * MINABNORM) )
238
+ {
239
+ sprintf(SE, " %d %.3f", v, Xv);
240
+ ExtendSiftEntry(SE);
241
+ }
242
+ }
243
+ ExtendSiftEntry(" 0");
244
+ }
245
+
246
+
247
+
248
+ void SaveContinCluster(float Mean, float SD, CaseCount Cases,
249
+ float LFrac, float LLim, float HFrac, float HLim)
250
+ /* ----------------- */
251
+ {
252
+ char SE[100];
253
+
254
+ SaveCondition();
255
+
256
+ sprintf(SE, "22 %d %g %g %g %.8g %g %.8g",
257
+ Cases, Mean, SD, LFrac, LLim, HFrac, HLim);
258
+ ExtendSiftEntry(SE);
259
+ }
260
+
261
+
262
+
263
+ /*************************************************************************/
264
+ /* */
265
+ /* Save attribute information */
266
+ /* */
267
+ /*************************************************************************/
268
+
269
+
270
+ void SaveNames()
271
+ /* --------- */
272
+ {
273
+ Attribute Att;
274
+ DiscrValue v;
275
+ int DN, Op;
276
+
277
+ fprintf(Sf, "atts=\"%d\"\n", MaxAtt);
278
+
279
+ ForEach(Att, 1, MaxAtt)
280
+ {
281
+ AsciiOut("att=", AttName[Att]);
282
+ fprintf(Sf, " sstat=\"%d\"", SpecialStatus[Att]);
283
+
284
+ if ( AttDef[Att] )
285
+ {
286
+ /* Dump definition */
287
+
288
+ fprintf(Sf, " def");
289
+ for ( DN = 0 ; ; DN++ )
290
+ {
291
+ Op = DefOp(AttDef[Att][DN]);
292
+
293
+ fprintf(Sf, "%c\"%d\"", ( DN ? ',' : '=' ), Op);
294
+ if ( Op == OP_ATT )
295
+ {
296
+ fprintf(Sf, ":\"%d\"",
297
+ (int) (long) DefSVal(AttDef[Att][DN]));
298
+ }
299
+ else
300
+ if ( Op == OP_STR )
301
+ {
302
+ AsciiOut(":", DefSVal(AttDef[Att][DN]));
303
+ }
304
+ else
305
+ {
306
+ fprintf(Sf, ":\"%g\"", DefNVal(AttDef[Att][DN]));
307
+ }
308
+
309
+ if ( Op == OP_END ) break;
310
+ }
311
+ }
312
+
313
+ if ( MaxAttVal[Att] > 0 )
314
+ {
315
+ AsciiOut(" elts=", AttValName[Att][2]); /* skip N/A */
316
+
317
+ ForEach(v, 3, MaxAttVal[Att])
318
+ {
319
+ AsciiOut(",", AttValName[Att][v]);
320
+ }
321
+ }
322
+
323
+ if ( Prec[Att] > 0 )
324
+ {
325
+ fprintf(Sf, " prec=\"%d\"", Prec[Att]);
326
+ }
327
+
328
+ fprintf(Sf, "\n");
329
+ }
330
+
331
+ if ( LabelAtt )
332
+ {
333
+ AsciiOut("label=", AttName[LabelAtt]);
334
+ fprintf(Sf, "\n");
335
+ }
336
+ }
337
+
338
+
339
+
340
+ /*************************************************************************/
341
+ /* */
342
+ /* Write ASCII string with prefix, escaping any quotes */
343
+ /* */
344
+ /*************************************************************************/
345
+
346
+
347
+ void AsciiOut(String Pre, String S)
348
+ /* -------- */
349
+ {
350
+ fprintf(Sf, "%s\"", Pre);
351
+ while ( *S )
352
+ {
353
+ if ( *S == '"' || *S == '\\' ) fputc('\\', Sf);
354
+ fputc(*S++, Sf);
355
+ }
356
+ fputc('"', Sf);
357
+ }
358
+ #endif
359
+
360
+
361
+
362
+ /*************************************************************************/
363
+ /* */
364
+ /* Read header information */
365
+ /* */
366
+ /*************************************************************************/
367
+
368
+
369
+ void ReadFilePrefix(String Extension)
370
+ /* -------------- */
371
+ {
372
+ Attribute Att=0;
373
+ DiscrValue v;
374
+ char *p, Dummy;
375
+ int Year, Month, Day, X, Elts, Op, DN, DefSize;
376
+ float A;
377
+ extern AttValue _UNK, _NA;
378
+
379
+ if ( ! (Sf = GetFile(Extension, "r")) ) Error(NOFILE, Fn, "");
380
+
381
+ while ( true )
382
+ {
383
+ switch ( ReadProp(&Dummy) )
384
+ {
385
+ case ERRORP:
386
+ Error(BADSIFT, PropName, "");
387
+ return;
388
+
389
+ case IDP:
390
+ /* Recover year run and set base date for timestamps */
391
+
392
+ if ( sscanf(PropVal + strlen(PropVal) - 11,
393
+ "%d-%d-%d\"", &Year, &Month, &Day) == 3 )
394
+ {
395
+ SetTSBase(Year);
396
+ }
397
+ break;
398
+
399
+ case ATTSP:
400
+ Unquoted = RemoveQuotes(PropVal);
401
+ if ( sscanf(Unquoted, "%d", &MaxAtt) != 1 )
402
+ {
403
+ Error(BADSIFT, "atts", "");
404
+ }
405
+
406
+ AttName = Alloc(MaxAtt+1, String);
407
+ SpecialStatus = AllocZero(MaxAtt+1, char);
408
+ AttDef = AllocZero(MaxAtt+1, Definition);
409
+ AttValName = Alloc(MaxAtt+1, String *);
410
+ MaxAttVal = AllocZero(MaxAtt+1, int);
411
+ Prec = Alloc(MaxAtt+1, unsigned char);
412
+ UseLogs = AllocZero(MaxAtt+1, Boolean);
413
+ LowTail = Alloc(MaxAtt+1, float);
414
+ HighTail = Alloc(MaxAtt+1, float);
415
+
416
+ Att = 0;
417
+ break;
418
+
419
+ case ATTP:
420
+ Att++;
421
+ if ( Att > MaxAtt )
422
+ {
423
+ Error(BADSIFT, "att", "");
424
+ }
425
+
426
+ Unquoted = RemoveQuotes(PropVal);
427
+ AttName[Att] = strdup(Unquoted);
428
+
429
+ LowTail[Att] = -1E38;
430
+ HighTail[Att] = 1E38;
431
+ break;
432
+
433
+ case SSTATP:
434
+ Unquoted = RemoveQuotes(PropVal);
435
+ if ( sscanf(Unquoted, "%d", &X) != 1 )
436
+ {
437
+ Error(BADSIFT, "sstat", "");
438
+ }
439
+ SpecialStatus[Att] = X;
440
+ break;
441
+
442
+ case ELTSP:
443
+ Elts = 100;
444
+ AttValName[Att] = Alloc(Elts, String);
445
+
446
+ MaxAttVal[Att] = 1;
447
+ AttValName[Att][1] = strdup("N/A");
448
+
449
+ for ( p = PropVal ; *p ; )
450
+ {
451
+ p = RemoveQuotes(p);
452
+ v = ++MaxAttVal[Att];
453
+
454
+ if ( v+2 >= Elts )
455
+ {
456
+ Elts += 100;
457
+ Realloc(AttValName[Att], Elts, String);
458
+ }
459
+
460
+ AttValName[Att][v] = strdup(p);
461
+
462
+ for ( p += strlen(p) ; *p != '"' ; p++ )
463
+ ;
464
+ p++;
465
+ if ( *p == ',' ) p++;
466
+ }
467
+ break;
468
+
469
+ case PRECP:
470
+ Unquoted = RemoveQuotes(PropVal);
471
+ if ( sscanf(Unquoted, "%d", &X) != 1 )
472
+ {
473
+ Error(BADSIFT, "prec", "");
474
+ }
475
+ Prec[Att] = X;
476
+ break;
477
+
478
+ case LABELP:
479
+ Unquoted = RemoveQuotes(PropVal);
480
+ LabelAtt = Which(Unquoted, AttName, 1, MaxAtt);
481
+ break;
482
+
483
+ case DEFP:
484
+ /* Make sure _UNK and _NA are set */
485
+
486
+ _UNK._discr_val = UNKNOWN;
487
+ _NA._discr_val = NA;
488
+
489
+ /* Allocate initial space for definition */
490
+
491
+ AttDef[Att] = AllocZero(DefSize = 100, DefElt);
492
+ DN = 0;
493
+
494
+ /* Read definition operators */
495
+
496
+ for ( p = PropVal ; *p ; )
497
+ {
498
+ /* Check that space is available */
499
+
500
+ if ( DN >= DefSize )
501
+ {
502
+ DefSize += 100;
503
+ Realloc(AttDef[Att], DefSize, DefElt);
504
+ }
505
+
506
+ /* Read opcode */
507
+
508
+ p = RemoveQuotes(p);
509
+ if ( sscanf(p, "%d", &Op) != 1 )
510
+ {
511
+ Error(BADSIFT, "def", "");
512
+ }
513
+ DefOp(AttDef[Att][DN]) = Op;
514
+
515
+ /* Move to start of operand */
516
+
517
+ for ( p += strlen(p) ; *p != '"' ; p++ )
518
+ ;
519
+ p++;
520
+ if ( *p != ':' )
521
+ {
522
+ Error(BADSIFT, "def", "");
523
+ }
524
+ p++;
525
+
526
+ /* Read operand -- depends on opcode */
527
+
528
+ p = RemoveQuotes(p);
529
+
530
+ if ( Op == OP_ATT )
531
+ {
532
+ if ( sscanf(p, "%d", &X) != 1 )
533
+ {
534
+ Error(BADSIFT, "def", "");
535
+ }
536
+ DefSVal(AttDef[Att][DN]) = (void *) X;
537
+ }
538
+ else
539
+ if ( Op == OP_STR )
540
+ {
541
+ DefSVal(AttDef[Att][DN]) = strdup(p);
542
+ }
543
+ else
544
+ {
545
+ if ( sscanf(p, "%g", &A) != 1 )
546
+ {
547
+ Error(BADSIFT, "def", "");
548
+ }
549
+ DefNVal(AttDef[Att][DN]) = A;
550
+ }
551
+
552
+ /* Get ready for next entry */
553
+
554
+ DN++;
555
+
556
+ for ( p += strlen(p) ; *p != '"' ; p++ )
557
+ ;
558
+ p++;
559
+ if ( *p == ',' ) p++;
560
+ }
561
+ break;
562
+
563
+ case MINABNORMP:
564
+ Unquoted = RemoveQuotes(PropVal);
565
+ if ( sscanf(Unquoted, "%g", &MINABNORM) != 1 )
566
+ {
567
+ Error(BADSIFT, "minabnorm", "");
568
+ }
569
+ return;
570
+ }
571
+ }
572
+ }
573
+
574
+
575
+
576
+ /*************************************************************************/
577
+ /* */
578
+ /* ASCII reading utilities */
579
+ /* */
580
+ /*************************************************************************/
581
+
582
+
583
+ int ReadProp(char *Delim)
584
+ /* -------- */
585
+ {
586
+ int c, i;
587
+ char *p;
588
+ Boolean Quote=false;
589
+
590
+ for ( p = PropName ; (c = fgetc(Sf)) != '=' ; )
591
+ {
592
+ if ( p - PropName >= 19 || c == EOF )
593
+ {
594
+ Error(BADSIFT, "EOF", "");
595
+ PropName[0] = PropVal[0] = *Delim = '\00';
596
+ return 0;
597
+ }
598
+ *p++ = c;
599
+ }
600
+ *p = '\00';
601
+
602
+ for ( p = PropVal ; ((c = fgetc(Sf)) != ' ' && c != '\n') || Quote ; )
603
+ {
604
+ if ( c == EOF )
605
+ {
606
+ Error(BADSIFT, "EOF", "");
607
+ PropName[0] = PropVal[0] = '\00';
608
+ return 0;
609
+ }
610
+
611
+ if ( (i = p - PropVal) >= PropValSize )
612
+ {
613
+ PropValSize += 10000;
614
+ Realloc(PropVal, PropValSize + 3, char);
615
+ p = PropVal + i;
616
+ }
617
+
618
+ *p++ = c;
619
+ if ( c == '\\' )
620
+ {
621
+ *p++ = fgetc(Sf);
622
+ }
623
+ else
624
+ if ( c == '"' )
625
+ {
626
+ Quote = ! Quote;
627
+ }
628
+ }
629
+ *p = '\00';
630
+ *Delim = c;
631
+
632
+ return Which(PropName, Prop, 1, PROPS);
633
+ }
634
+
635
+
636
+
637
+ String RemoveQuotes(String S)
638
+ /* ------------ */
639
+ {
640
+ char *p, *Start;
641
+
642
+ p = Start = S;
643
+
644
+ for ( S++ ; *S != '"' ; S++ )
645
+ {
646
+ if ( *S == '\\' ) S++;
647
+ *p++ = *S;
648
+ *S = '-';
649
+ }
650
+ *p = '\00';
651
+
652
+ return Start;
653
+ }
654
+
655
+
656
+
657
+ /*************************************************************************/
658
+ /* */
659
+ /* Add more text to a sift entry */
660
+ /* */
661
+ /*************************************************************************/
662
+
663
+
664
+ void ExtendSiftEntry(String S)
665
+ /* --------------- */
666
+ {
667
+ int Len;
668
+
669
+ /* Make sure there is enough room */
670
+
671
+ if ( (Len = strlen(S)) >= GEnv.SiftSpace - GEnv.SiftSize )
672
+ {
673
+ GEnv.SiftSpace += 1000;
674
+
675
+ if ( GEnv.SiftEntry )
676
+ {
677
+ Realloc(GEnv.SiftEntry, GEnv.SiftSpace, char);
678
+ }
679
+ else
680
+ {
681
+ GEnv.SiftEntry = Alloc(GEnv.SiftSpace, char);
682
+ }
683
+ }
684
+
685
+ strcpy(GEnv.SiftEntry + GEnv.SiftSize, S);
686
+ GEnv.SiftSize += Len;
687
+ }