see5-installer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }