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,159 @@
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
+ /* Text strings for UTF-8 internationalization */
30
+ /* ------------------------------------------- */
31
+ /* */
32
+ /*************************************************************************/
33
+
34
+
35
+ /* General stuff */
36
+
37
+
38
+ #ifdef UTF8
39
+ #define CharWidth(S) UTF8CharWidth(S)
40
+ #else
41
+ #define CharWidth(S) (int) strlen(S)
42
+ #endif
43
+
44
+ /* Strings etc */
45
+
46
+ #define T_GritBot "GritBot"
47
+ #define F_Release(n) "Release " n
48
+
49
+ #define T_Options "Options"
50
+ #define F_Application "\tApplication `%s'\n"
51
+ #define F_Filtering "\tFiltering level %g%%\n"
52
+ #define F_MaxConds "\tMaxium %d conditions in description\n"
53
+ #define F_MinSubset "\tMinimum %d cases in subset\n"
54
+ #define F_MaxOut "\tShow up to %d possible anomalies\n"
55
+ #define F_NoSift "\tDo not save analysis in .sift file\n"
56
+ #define F_ListAnoms "\tSave case numbers of possible anomalies\n"
57
+ #define F_UnrecogOpt "\n ** Unrecognised option %s"\
58
+ "\n ** Summary of options for GritBot:\n"
59
+ #define F_OptList "\t-f <filestem>\tapplication filestem\n"\
60
+ "\t-l <percent>\tfiltering level\n"\
61
+ "\t-c <integer>\tmaximum conditions in"\
62
+ " description\n"\
63
+ "\t-n <cases>\tlimit number of possible"\
64
+ " anomalies reported\n"\
65
+ "\t-s\t\tdo not save .sift file\n"\
66
+ "\t-r\t\trecord case numbers of"\
67
+ " possible anomalies\n"\
68
+ "\t-h\t\tprint this message\n"
69
+ #define F_ReadData(c,a,f) "\nRead %d cases (%d attributes) from"\
70
+ " %s.data\n", c, a, f
71
+ #define F_ReadTest(c,f) "Read %d cases from %s.test\n", c, f
72
+ #define F_AttChecked "\nAttributes checked:\n"
73
+ #define F_AttNotChecked "\nAttributes not checked:\n"
74
+ #define F_Time(s) "\n\nTime: %.1f secs\n", s
75
+
76
+ #define F_WhileCheck "\n while checking %s:\n"
77
+ #define F_ExcludeMissing(a) ( (a) > 1 ?\
78
+ "\texcluding %d missing values\n" :\
79
+ "\texcluding %d missing value\n" ), a
80
+ #define F_ExcludeNA(a) ( (a) > 1 ?\
81
+ "\texcluding %d N/A values\n" :\
82
+ "\texcluding %d N/A value\n" ), a
83
+ #define F_TooManyIdentical "\ttoo many identical values -- excluded\n"
84
+ #define F_LowTail(c,t) "\texcluding low tail (%d cases below %s)\n",\
85
+ c, t
86
+ #define F_HighTail(c,t) "\texcluding high tail (%d cases above %s)\n",\
87
+ c, t
88
+
89
+ #define F_WarnDemo "\n\t** This demonstration version cannot"\
90
+ " process **\n"\
91
+ "\t** more than %d training or test cases."\
92
+ " **\n"\
93
+
94
+ #define F_PossAnomalies(a) ( (a) != 1 ?\
95
+ "\n%d possible anomalies identified\n" :\
96
+ "\n%d possible anomaly identified\n" ), a
97
+ #define F_NoTestCase(c) "\ntest case %d:", c
98
+ #define F_NoDataCase(c) "\ndata case %d:", c
99
+ #define F_NoCase(c) "\ncase %d:", c
100
+ #define F_LabelCase(l) " (label %s)", l
101
+ #define F_Cases(c) " (%d cases, ", c
102
+ #define F_CvGroup(m,d,p,r,v) "mean %s, %.*f%% %s %s)\n", m, d, p, r, v
103
+ #define F_DvGroup(d,p,v) "%.*f%% `%s')\n", d, p, v
104
+ #define T_and "and"
105
+ #define T_in "in" /* element of set */
106
+
107
+ #define T_ReadTrain "Reading training data"
108
+ #define T_ReadTest "Reading test data"
109
+ #define T_Prelim "Preliminaries"
110
+ #define T_Checking "Checking"
111
+ #define T_Reporting "Reporting anomalies"
112
+ #define T_CleaningUp "Cleaning up"
113
+ #define F_Preliminaries "Preliminaries for %-21.21s\n"
114
+ #define F_Checking(a,x,y,c) "Checking %-21.21s %s%s (%d cases"\
115
+ " checked)\n", a, x, y, c
116
+
117
+ #define F_Line(l,f) "*** line %d of `%s': ", l, f
118
+ #define E_NOFILE(f,e) "cannot open file %s%s\n", f, e
119
+ #define E_ForWrite " for writing"
120
+ #define E_BADATTNAME "`:' or `:=' expected after attribute name"\
121
+ " `%s'\n"
122
+ #define E_UNKNOWNATT "unknown attribute name `%s'\n"
123
+ #define E_EOFINATT "unexpected eof while reading attribute `%s'\n"
124
+ #define E_SINGLEATTVAL(a,v) "attribute `%s' has only one value `%s'\n",\
125
+ a, v
126
+ #define E_DUPATTNAME "multiple attributes with name `%s'\n"
127
+ #define E_BADATTVAL(v,a) "bad value of `%s' for attribute `%s'\n", v, a
128
+ #define E_BADNUMBER(a) "value of `%s' changed to `?'\n", a
129
+ #define E_BADCLASS "bad class value `%s'l\n"
130
+ #define E_NOMEM "unable to allocate sufficient memory\n"
131
+ #define E_TOOMANYVALS(a,n) "too many values for attribute `%s'"\
132
+ " (max %d)\n", a, n
133
+ #define E_BADDISCRETE "bad number of discrete values for attribute"\
134
+ " `%s'\n"
135
+ #define E_LONGNAME "overlength name: check data file formats\n"
136
+ #define E_HITEOF "unexpected end of file\n"
137
+ #define E_MISSNAME "missing name or value before `%s'\n"
138
+ #define E_BADTSTMP(d,a) "bad timestamp `%s' for attribute `%s'\n", d, a
139
+ #define E_BADDATE(d,a) "bad date `%s' for attribute `%s'\n", d, a
140
+ #define E_BADTIME(d,a) "bad time `%s' for attribute `%s'\n", d, a
141
+ #define E_BADDEF1(a,s,x) "in definition of attribute `%s':\n"\
142
+ "\tat `%.12s': expect %s\n", a, s, x
143
+ #define E_BADDEF2(a,s,x) "in definition of attribute `%s':\n"\
144
+ "\t`%s': %s\n", a, s, x
145
+ #define E_SAMEATT(a,b) "attribute `%s' is identical to attribute"\
146
+ " `%s'\n", a, b
147
+ #define E_BADDEF3 "cannot define target attribute `%s'\n"
148
+ #define E_SIFT "sift file corrupted (entry \"%s\")\n"
149
+ #define T_ErrorLimit "\nError limit exceeded\n"
150
+
151
+ #define F_CkOptList "\t-f <filestem>\tapplication filestem\n"\
152
+ "\t-n <cases>\tlimit number of possible"\
153
+ " anomalies reported\n"\
154
+ "\t-r\t\trecord case numbers of"\
155
+ " possible anomalies\n"\
156
+ "\t-h\t\tprint this message\n"
157
+ #define F_ReadSift "\nRead saved analysis from %s.sift\n"
158
+ #define F_ReadCases(c,a,f) "Read %d cases (%d attributes) from"\
159
+ " %s.cases\n", c, a, f
@@ -0,0 +1,126 @@
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 that provide information on progress */
30
+ /* --------------------------------------------- */
31
+ /* */
32
+ /*************************************************************************/
33
+
34
+
35
+ #include "defns.i"
36
+ #include "extern.i"
37
+
38
+
39
+ int Stage=0; /* Current stage number */
40
+ FILE *Uf=0; /* File to which update info written */
41
+
42
+
43
+ /*************************************************************************/
44
+ /* */
45
+ /* There are five stages (see messages in Progress() below) */
46
+ /* Record stage and open update file if necessary */
47
+ /* */
48
+ /*************************************************************************/
49
+
50
+
51
+ void NotifyStage(int S)
52
+ /* ----------- */
53
+ {
54
+ Stage = S;
55
+ if ( S == 1 )
56
+ {
57
+ if ( ! (Uf = GetFile(".tmp", "w")) ) Error(NOFILE, "", " for writing");
58
+ }
59
+ }
60
+
61
+
62
+
63
+ /*************************************************************************/
64
+ /* */
65
+ /* Print progress message. This routine is called in two ways: */
66
+ /* * negative Delta = measure of total effort required for stage */
67
+ /* * positive Delta = increment since last call */
68
+ /* */
69
+ /*************************************************************************/
70
+
71
+
72
+ void Progress(int Delta)
73
+ /* -------- */
74
+ {
75
+ static int Att, Current=0, Twentieth=0, LastStage=0;
76
+ int p;
77
+ static char *Message[]={ "",
78
+ T_ReadTrain,
79
+ T_ReadTest,
80
+ T_Prelim,
81
+ T_Checking,
82
+ T_Reporting,
83
+ T_CleaningUp },
84
+ *Done=">>>>>>>>>>>>>>>>>>>>",
85
+ *ToDo="....................";
86
+
87
+ if ( ! Uf ) return;
88
+
89
+ if ( Delta < 0)
90
+ {
91
+ Att = -Delta;
92
+ Current = 0;
93
+ Twentieth = -1;
94
+
95
+ if ( Stage == PRELIM )
96
+ {
97
+ fprintf(Uf, F_Preliminaries, AttName[Att]);
98
+ fflush(Uf);
99
+ }
100
+ }
101
+ else
102
+ {
103
+ Current = Min(MaxCase+1, Current + Delta);
104
+ }
105
+
106
+ if ( Stage != PRELIM &&
107
+ ( (p = rint((20.0 * Current) / (MaxCase+1.01))) != Twentieth ||
108
+ Stage != LastStage ) )
109
+ {
110
+ LastStage = Stage;
111
+ Twentieth = p;
112
+
113
+ if ( Stage == CHECKING )
114
+ {
115
+ fprintf(Uf, F_Checking(AttName[Att],
116
+ Done + (20 - Twentieth), ToDo + Twentieth,
117
+ Current));
118
+ }
119
+ else
120
+ {
121
+ fprintf(Uf, "%s\n", Message[Stage]);
122
+ }
123
+
124
+ fflush(Uf);
125
+ }
126
+ }
@@ -0,0 +1,1029 @@
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
+ /* Print header for all programs */
30
+ /* ----------------------------- */
31
+ /* */
32
+ /*************************************************************************/
33
+
34
+ #include "defns.i"
35
+ #include "extern.i"
36
+
37
+ #include <sys/unistd.h>
38
+
39
+
40
+ void PrintHeader(String Title)
41
+ /* ----------- */
42
+ {
43
+ char TitleLine[80];
44
+ time_t clock;
45
+ int Underline;
46
+
47
+ clock = time(0);
48
+ sprintf(TitleLine, "%s%s [%s]", T_GritBot, Title, F_Release(RELEASE));
49
+ fprintf(Of, "\n%s \t%s", TitleLine, ctime(&clock));
50
+
51
+ Underline = CharWidth(TitleLine);
52
+ while ( Underline-- ) putc('-', Of);
53
+ putc('\n', Of);
54
+ }
55
+
56
+
57
+
58
+ /*************************************************************************/
59
+ /* */
60
+ /* This is a specialised form of the getopt utility. */
61
+ /* */
62
+ /*************************************************************************/
63
+
64
+
65
+ String OptArg, Option;
66
+
67
+
68
+ char ProcessOption(int Argc, char *Argv[], char *Options)
69
+ /* ------------- */
70
+ {
71
+ int i;
72
+ static int OptNo=1;
73
+
74
+ if ( OptNo >= Argc ) return '\00';
75
+
76
+ if ( *(Option = Argv[OptNo++]) != '-' ) return '?';
77
+
78
+ for ( i = 0 ; Options[i] ; i++ )
79
+ {
80
+ if ( Options[i] == Option[1] )
81
+ {
82
+ OptArg = ( Options[i+1] != '+' ? Nil :
83
+ Option[2] ? Option+2 :
84
+ OptNo < Argc ? Argv[OptNo++] : "0" );
85
+ return Option[1];
86
+ }
87
+ }
88
+
89
+ return '?';
90
+ }
91
+
92
+
93
+
94
+ /*************************************************************************/
95
+ /* */
96
+ /* Protected memory allocation routines */
97
+ /* */
98
+ /*************************************************************************/
99
+
100
+
101
+
102
+ void *Pmalloc(size_t Bytes)
103
+ /* ------- */
104
+ {
105
+ void *p=Nil;
106
+
107
+ if ( ! Bytes || (p = (void *) malloc(Bytes)) )
108
+ {
109
+ return p;
110
+ }
111
+
112
+ Error(NOMEM, "", "");
113
+
114
+ }
115
+
116
+
117
+
118
+ void *Prealloc(void *Present, size_t Bytes)
119
+ /* -------- */
120
+ {
121
+ void *p=Nil;
122
+
123
+ if ( ! Bytes ) return Nil;
124
+
125
+ if ( ! Present ) return Pmalloc(Bytes);
126
+
127
+ if ( (p = (void *) realloc(Present, Bytes)) )
128
+ {
129
+ return p;
130
+ }
131
+
132
+ Error(NOMEM, "", "");
133
+
134
+ }
135
+
136
+
137
+
138
+ void *Pcalloc(size_t Number, unsigned int Size)
139
+ /* ------- */
140
+ {
141
+ void *p=Nil;
142
+
143
+ if ( ! Number || (p = (void *) calloc(Number, Size)) )
144
+ {
145
+ return p;
146
+ }
147
+
148
+ Error(NOMEM, "", "");
149
+
150
+ }
151
+
152
+
153
+
154
+ void FreeVector(void **V, int First, int Last)
155
+ /* ---------- */
156
+ {
157
+ if ( V )
158
+ {
159
+ while ( First <= Last )
160
+ {
161
+ FreeUnlessNil(V[First]);
162
+ First++;
163
+ }
164
+
165
+ Free(V);
166
+ }
167
+ }
168
+
169
+
170
+
171
+ /*************************************************************************/
172
+ /* */
173
+ /* Special memory allocation routines for case memory */
174
+ /* */
175
+ /*************************************************************************/
176
+
177
+ typedef struct _datablockrec *DataBlock;
178
+
179
+ typedef struct _datablockrec
180
+ {
181
+ Description Head; /* first address */
182
+ int Allocated; /* number of cases in this block */
183
+ DataBlock Prev; /* previous data block */
184
+ }
185
+ DataBlockRec;
186
+
187
+ DataBlock DataMem=Nil;
188
+ int DataBlockSize=0;
189
+
190
+
191
+
192
+ Description NewCase()
193
+ /* ------- */
194
+ {
195
+ DataBlock Prev;
196
+
197
+ if ( ! DataMem || DataMem->Allocated == DataBlockSize )
198
+ {
199
+ DataBlockSize = Min(8192, 262144 / (MaxAtt+3) + 1);
200
+
201
+ Prev = DataMem;
202
+ DataMem = AllocZero(1, DataBlockRec);
203
+ DataMem->Head = Alloc(DataBlockSize * (MaxAtt+3), AttValue);
204
+ DataMem->Prev = Prev;
205
+ }
206
+
207
+ return DataMem->Head + (DataMem->Allocated++) * (MaxAtt+3);
208
+ }
209
+
210
+
211
+
212
+ void MemTrim()
213
+ /* ------- */
214
+ {
215
+ Realloc(DataMem->Head, DataMem->Allocated * (MaxAtt+3), AttValue);
216
+ }
217
+
218
+
219
+
220
+ void FreeCases()
221
+ /* --------- */
222
+ {
223
+ DataBlock Prev;
224
+
225
+ while ( DataMem )
226
+ {
227
+ Prev = DataMem->Prev;
228
+ Free(DataMem->Head);
229
+ Free(DataMem);
230
+ DataMem = Prev;
231
+ }
232
+ }
233
+
234
+
235
+
236
+ void FreeLastCase(Description Case)
237
+ /* ------------ */
238
+ {
239
+ Attribute Att;
240
+
241
+ ForEach(Att, 1, MaxAtt)
242
+ {
243
+ if ( Exclude(Att) ) Free(SVal(Case,Att));
244
+ }
245
+
246
+ DataMem->Allocated--;
247
+ }
248
+
249
+
250
+
251
+ /*************************************************************************/
252
+ /* */
253
+ /* Generate uniform random numbers */
254
+ /* */
255
+ /*************************************************************************/
256
+
257
+
258
+ #define Modify(F,S) if ( (F -= S) < 0 ) F += 1.0
259
+
260
+ int KRFp=0, KRSp=0;
261
+
262
+ double KRandom()
263
+ /* ------- */
264
+ {
265
+ static double URD[55];
266
+ double V1, V2;
267
+ int i, j;
268
+
269
+ /* Initialisation */
270
+
271
+ if ( KRFp == KRSp )
272
+ {
273
+ KRFp = 0;
274
+ KRSp = 31;
275
+
276
+ V1 = 1.0;
277
+ V2 = 0.314159285;
278
+
279
+ ForEach(i, 1, 55)
280
+ {
281
+ URD[ j = (i * 21) % 55 ] = V1;
282
+ V1 = V2 - V1;
283
+ if ( V1 < 0 ) V1 += 1.0;
284
+ V2 = URD[j];
285
+ }
286
+
287
+ ForEach(j, 0, 5)
288
+ {
289
+ ForEach(i, 0, 54)
290
+ {
291
+ Modify(URD[i], URD[(i+30) % 55]);
292
+ }
293
+ }
294
+ }
295
+
296
+ KRFp = (KRFp + 1) % 55;
297
+ KRSp = (KRSp + 1) % 55;
298
+ Modify(URD[KRFp], URD[KRSp]);
299
+
300
+ return URD[KRFp];
301
+ }
302
+
303
+
304
+
305
+ void ResetKR(int KRInit)
306
+ /* ------- */
307
+ {
308
+ KRFp = KRSp = 0;
309
+
310
+ KRInit += 1000;
311
+ while ( KRInit-- )
312
+ {
313
+ KRandom();
314
+ }
315
+ }
316
+
317
+
318
+
319
+ /*************************************************************************/
320
+ /* */
321
+ /* Error messages */
322
+ /* */
323
+ /*************************************************************************/
324
+
325
+
326
+ void Error(int ErrNo, String S1, String S2)
327
+ /* ----- */
328
+ {
329
+ Boolean Quit=false;
330
+
331
+
332
+ if ( ! Of ) return;
333
+
334
+ if ( ! ErrMsgs )
335
+ {
336
+ fprintf(Of, "\n");
337
+ }
338
+
339
+ if ( ErrNo == NOFILE || ErrNo == NOMEM || ErrNo == BADSIFT )
340
+ {
341
+ fprintf(Of, "*** ");
342
+ }
343
+ else
344
+ {
345
+ fprintf(Of, F_Line(LineNo, Fn));
346
+ }
347
+
348
+ switch ( ErrNo )
349
+ {
350
+ case NOFILE:
351
+ fprintf(Of, E_NOFILE(Fn, S2));
352
+ Quit = true;
353
+ break;
354
+
355
+ case BADATTNAME:
356
+ fprintf(Of, E_BADATTNAME, S1);
357
+ break;
358
+
359
+ case UNKNOWNATT:
360
+ fprintf(Of, E_UNKNOWNATT, S1);
361
+ break;
362
+
363
+ case EOFINATT:
364
+ fprintf(Of, E_EOFINATT, S1);
365
+ break;
366
+
367
+ case SINGLEATTVAL:
368
+ fprintf(Of, E_SINGLEATTVAL(S1, S2));
369
+ break;
370
+
371
+ case DUPATTNAME:
372
+ fprintf(Of, E_DUPATTNAME, S1);
373
+ break;
374
+
375
+ case BADATTVAL:
376
+ fprintf(Of, E_BADATTVAL(S2, S1));
377
+ break;
378
+
379
+ case BADNUMBER:
380
+ fprintf(Of, E_BADNUMBER(S1));
381
+ break;
382
+
383
+ case BADCLASS:
384
+ fprintf(Of, E_BADCLASS, S2);
385
+ break;
386
+
387
+ case NOMEM:
388
+ fprintf(Of, E_NOMEM);
389
+ Quit = true;
390
+ break;
391
+
392
+ case TOOMANYVALS:
393
+ fprintf(Of, E_TOOMANYVALS(S1, (int) S2));
394
+ break;
395
+
396
+ case BADDISCRETE:
397
+ fprintf(Of, E_BADDISCRETE, S1);
398
+ break;
399
+
400
+ case LONGNAME:
401
+ fprintf(Of, E_LONGNAME);
402
+ Quit = true;
403
+ break;
404
+
405
+ case HITEOF:
406
+ fprintf(Of, E_HITEOF);
407
+ break;
408
+
409
+ case MISSNAME:
410
+ fprintf(Of, E_MISSNAME, S2);
411
+ break;
412
+
413
+ case BADTSTMP:
414
+ fprintf(Of, E_BADTSTMP(S2, S1));
415
+ break;
416
+
417
+ case BADDATE:
418
+ fprintf(Of, E_BADDATE(S2, S1));
419
+ break;
420
+
421
+ case BADTIME:
422
+ fprintf(Of, E_BADTIME(S2, S1));
423
+ break;
424
+
425
+ case BADDEF1:
426
+ fprintf(Of, E_BADDEF1(AttName[MaxAtt], S1, S2));
427
+ break;
428
+
429
+ case BADDEF2:
430
+ fprintf(Of, E_BADDEF2(AttName[MaxAtt], S1, S2));
431
+ break;
432
+
433
+ case SAMEATT:
434
+ fprintf(Of, E_SAMEATT(AttName[MaxAtt], S1));
435
+ break;
436
+
437
+ case BADDEF3:
438
+ fprintf(Of, E_BADDEF3, AttName[MaxAtt]);
439
+ break;
440
+
441
+ case BADSIFT:
442
+ fprintf(Of, E_SIFT, S1);
443
+ Quit = true;
444
+ break;
445
+ }
446
+
447
+ if ( ++ErrMsgs > 10 )
448
+ {
449
+ fprintf(Of, T_ErrorLimit);
450
+ MaxCase--;
451
+ Quit = true;
452
+ }
453
+
454
+ if ( Quit )
455
+ {
456
+ Goodbye(1);
457
+ }
458
+ }
459
+
460
+
461
+
462
+ /*************************************************************************/
463
+ /* */
464
+ /* Generate the label for a case */
465
+ /* */
466
+ /*************************************************************************/
467
+
468
+ char LabelBuffer[1000];
469
+
470
+
471
+ String CaseLabel(CaseNo N)
472
+ /* --------- */
473
+ {
474
+ String p;
475
+
476
+ if ( LabelAtt && (p = SVal(Case[N], LabelAtt)) )
477
+ ;
478
+ else
479
+ {
480
+ sprintf(LabelBuffer, "#%d", N+1);
481
+ p = LabelBuffer;
482
+ }
483
+
484
+ return p;
485
+ }
486
+
487
+
488
+
489
+ /*************************************************************************/
490
+ /* */
491
+ /* Open file with given extension for read/write */
492
+ /* */
493
+ /*************************************************************************/
494
+
495
+
496
+ FILE *GetFile(String Extension, String RW)
497
+ /* -------- */
498
+ {
499
+ strcpy(Fn, FileStem);
500
+ strcat(Fn, Extension);
501
+ return fopen(Fn, RW);
502
+ }
503
+
504
+
505
+
506
+ /*************************************************************************/
507
+ /* */
508
+ /* Determine total elapsed time so far. */
509
+ /* */
510
+ /*************************************************************************/
511
+
512
+
513
+ //#include <sys/resource.h>
514
+ #include <sys/time.h>
515
+
516
+ double ExecTime()
517
+ /* -------- */
518
+ {
519
+ struct timeval TV;
520
+ struct timezone TZ={0,0};
521
+
522
+ gettimeofday(&TV, &TZ);
523
+ return TV.tv_sec + TV.tv_usec / 1000000.0;
524
+ }
525
+
526
+
527
+
528
+
529
+
530
+
531
+ /*************************************************************************/
532
+ /* */
533
+ /* Determine precision of numeric value */
534
+ /* */
535
+ /*************************************************************************/
536
+
537
+
538
+ int Denominator(ContValue Val)
539
+ /* ----------- */
540
+ {
541
+ double RoundErr, Accuracy;
542
+ int Mult;
543
+
544
+ Accuracy = fabs(Val) * 1E-6; /* approximate */
545
+ Val = modf(Val, &RoundErr);
546
+
547
+ for ( Mult = 100000 ; Mult >= 1 ; Mult /= 10 )
548
+ {
549
+ RoundErr = fabs(rint(Val * Mult) / Mult - Val);
550
+ if ( RoundErr > 2 * Accuracy )
551
+ {
552
+ return Mult * 10;
553
+ }
554
+ }
555
+
556
+ return 1;
557
+ }
558
+
559
+
560
+ int FracBase(Attribute Att)
561
+ /* -------- */
562
+ {
563
+ CaseNo i;
564
+ int Denom=0, ThisDenom;
565
+
566
+ ForEach(i, 0, MaxCase)
567
+ {
568
+ if ( ! Unknown(Case[i], Att) &&
569
+ ! NotApplic(Case[i], Att) &&
570
+ (ThisDenom = Denominator(CVal(Case[i], Att))) > Denom )
571
+ {
572
+ Denom = ThisDenom;
573
+ }
574
+ }
575
+
576
+ return Denom;
577
+ }
578
+
579
+
580
+
581
+ /*************************************************************************/
582
+ /* */
583
+ /* Routines to process date (Algorithm due to Gauss?) */
584
+ /* */
585
+ /*************************************************************************/
586
+
587
+
588
+ int GetInt(String S, int N)
589
+ /* ------ */
590
+ {
591
+ int Result=0;
592
+
593
+ while ( N-- )
594
+ {
595
+ if ( ! isdigit(*S) ) return 0;
596
+
597
+ Result = Result * 10 + (*S++ - '0');
598
+ }
599
+
600
+ return Result;
601
+ }
602
+
603
+
604
+ int DateToDay(String DS) /* Day 1 is 0000/03/01 */
605
+ /* --------- */
606
+ {
607
+ int Year, Month, Day;
608
+
609
+ if ( strlen(DS) != 10 ) return 0;
610
+
611
+ Year = GetInt(DS, 4);
612
+ Month = GetInt(DS+5, 2);
613
+ Day = GetInt(DS+8, 2);
614
+
615
+ if ( ! ( DS[4] == '/' && DS[7] == '/' || DS[4] == '-' && DS[7] == '-' ) ||
616
+ Year < 0 || Month < 1 || Day < 1 ||
617
+ Month > 12 ||
618
+ Day > 31 ||
619
+ Day > 30 &&
620
+ ( Month == 4 || Month == 6 || Month == 9 || Month == 11 ) ||
621
+ Month == 2 &&
622
+ ( Day > 29 ||
623
+ Day > 28 && ( Year % 4 != 0 ||
624
+ Year % 100 == 0 && Year % 400 != 0 ) ) )
625
+ {
626
+ return 0;
627
+ }
628
+
629
+ if ( (Month -= 2) <= 0 )
630
+ {
631
+ Month += 12;
632
+ Year -= 1;
633
+ }
634
+
635
+ return Year * 365 + Year / 4 - Year / 100 + Year / 400
636
+ + 367 * Month / 12
637
+ + Day - 30;
638
+ }
639
+
640
+
641
+
642
+ void DayToDate(int Day, String Date)
643
+ /* --------- */
644
+ {
645
+ int Year, Month, OrigDay=Day;
646
+
647
+ if ( Day <= 0 )
648
+ {
649
+ strcpy(Date, "?");
650
+ return;
651
+ }
652
+
653
+ Year = (Day - 1) / 365.2425L; /* Year = completed years */
654
+ Day -= Year * 365 + Year / 4 - Year / 100 + Year / 400;
655
+
656
+ if ( Day < 1 )
657
+ {
658
+ Year--;
659
+ Day = OrigDay - (Year * 365 + Year / 4 - Year / 100 + Year / 400);
660
+ }
661
+ else
662
+ if ( Day > 366 ||
663
+ Day == 366 &&
664
+ ( (Year+1) % 4 != 0 || (Year+1) % 100 == 0 && (Year+1) % 400 != 0 ) )
665
+ {
666
+ Year++;
667
+ Day = OrigDay - (Year * 365 + Year / 4 - Year / 100 + Year / 400);
668
+ }
669
+
670
+ Month = (Day + 30) * 12 / 367;
671
+ Day -= 367 * Month / 12 - 30;
672
+ if ( Day < 1 )
673
+ {
674
+ Month = 11;
675
+ Day = 31;
676
+ }
677
+
678
+ Month += 2;
679
+ if ( Month > 12 )
680
+ {
681
+ Month -= 12;
682
+ Year++;
683
+ }
684
+
685
+ sprintf(Date, "%d/%d%d/%d%d", Year, Month/10, Month % 10, Day/10, Day % 10);
686
+ }
687
+
688
+
689
+
690
+ /*************************************************************************/
691
+ /* */
692
+ /* Routines to process clock time and timestamps */
693
+ /* */
694
+ /*************************************************************************/
695
+
696
+
697
+ int TimeToSecs(String TS)
698
+ /* ---------- */
699
+ {
700
+ int Hour, Mins, Secs;
701
+
702
+ if ( strlen(TS) != 8 ) return -1;
703
+
704
+ Hour = GetInt(TS, 2);
705
+ Mins = GetInt(TS+3, 2);
706
+ Secs = GetInt(TS+6, 2);
707
+
708
+ if ( TS[2] != ':' || TS[5] != ':' ||
709
+ Hour >= 24 || Mins >= 60 || Secs >= 60 )
710
+ {
711
+ return -1;
712
+ }
713
+
714
+ return Hour * 3600 + Mins * 60 + Secs;
715
+ }
716
+
717
+
718
+
719
+ void SecsToTime(int Secs, String Time)
720
+ /* ---------- */
721
+ {
722
+ int Hour, Mins;
723
+
724
+ Hour = Secs / 3600;
725
+ Mins = (Secs % 3600) / 60;
726
+ Secs = Secs % 60;
727
+
728
+ sprintf(Time, "%d%d:%d%d:%d%d",
729
+ Hour / 10, Hour % 10,
730
+ Mins / 10, Mins % 10,
731
+ Secs / 10, Secs % 10);
732
+ }
733
+
734
+
735
+
736
+ void SetTSBase(int y)
737
+ /* --------- */
738
+ {
739
+ y -= 15;
740
+ TSBase = y * 365 + y / 4 - y / 100 + y / 400 + (367 * 4) / 12 + 1 - 30;
741
+ }
742
+
743
+
744
+
745
+ int TStampToMins(String TS)
746
+ /* ------------ */
747
+ {
748
+ int Day, Sec, i;
749
+
750
+ /* Check for reasonable length and space between date and time */
751
+
752
+ if ( strlen(TS) < 19 || ! Space(TS[10]) ) return (1 << 30);
753
+
754
+ /* Read date part */
755
+
756
+ TS[10] = '\00';
757
+ Day = DateToDay(TS);
758
+ TS[10] = ' ';
759
+
760
+ /* Skip one or more spaces */
761
+
762
+ for ( i = 11 ; TS[i] && Space(TS[i]) ; i++ )
763
+ ;
764
+
765
+ /* Read time part */
766
+
767
+ Sec = TimeToSecs(TS+i);
768
+
769
+ /* Return a long time in the future if there is an error */
770
+
771
+ return ( Day < 1 || Sec < 0 ? (1 << 30) :
772
+ (Day - TSBase) * 1440 + (Sec + 30) / 60 );
773
+ }
774
+
775
+
776
+
777
+ /*************************************************************************/
778
+ /* */
779
+ /* Convert a continuous value to a string. DS must be */
780
+ /* large enough to hold any value (e.g. a date, time, ...) */
781
+ /* */
782
+ /*************************************************************************/
783
+
784
+
785
+ void CValToStr(ContValue CV, Attribute Att, String DS)
786
+ /* --------- */
787
+ {
788
+ int Mins;
789
+
790
+ if ( TStampVal(Att) )
791
+ {
792
+ DayToDate(floor(CV / 1440) + TSBase, DS);
793
+ DS[10] = ' ';
794
+ Mins = rint(CV) - floor(CV / 1440) * 1440;
795
+ SecsToTime(Mins * 60, DS+11);
796
+ }
797
+ else
798
+ if ( DateVal(Att) )
799
+ {
800
+ DayToDate(CV, DS);
801
+ }
802
+ else
803
+ if ( TimeVal(Att) )
804
+ {
805
+ SecsToTime(CV, DS);
806
+ }
807
+ else
808
+ {
809
+ sprintf(DS, "%.*g", PREC, CV);
810
+ }
811
+ }
812
+
813
+
814
+
815
+ /*************************************************************************/
816
+ /* */
817
+ /* Check option value */
818
+ /* */
819
+ /*************************************************************************/
820
+
821
+
822
+ void Check(float Val, float Low, float High)
823
+ /* ----- */
824
+ {
825
+ if ( Val < Low || Val > High )
826
+ {
827
+ printf("\t** illegal value %g -- should be between %g and %g\n",
828
+ Val, Low, High);
829
+ exit(1);
830
+ }
831
+ }
832
+
833
+
834
+
835
+ #ifdef UTF8
836
+ ///////////////////////////////////////////////////////////////////////////
837
+ // //
838
+ // Routines for Unicode/UTF-8 processing //
839
+ // ------------------------------------- //
840
+ // //
841
+ ///////////////////////////////////////////////////////////////////////////
842
+
843
+ #include <wchar.h>
844
+
845
+
846
+
847
+ /*************************************************************************/
848
+ /* */
849
+ /* Determine the total character width of a UTF-8 string */
850
+ /* */
851
+ /*************************************************************************/
852
+
853
+
854
+ int UTF8CharWidth(unsigned char *U)
855
+ /* ------------- */
856
+ {
857
+ int CWidth=0, Mask, This;
858
+ wchar_t Unicode;
859
+
860
+ while ( *U )
861
+ {
862
+ Unicode = *U;
863
+
864
+ if ( *U < 0x7F )
865
+ {
866
+ /* ASCII character */
867
+
868
+ CWidth++;
869
+ U++;
870
+ }
871
+ else
872
+ {
873
+ /* Discard header bits */
874
+
875
+ Mask = 0x80;
876
+ while ( Unicode & Mask )
877
+ {
878
+ Unicode ^= Mask;
879
+ Mask = Mask >> 1;
880
+ }
881
+
882
+ while ( ((*(++U)) & 0xc0) == 0x80 )
883
+ {
884
+ Unicode = (Unicode << 6) | (*U & 0x3f);
885
+ }
886
+
887
+ if ( (This = wcwidth(Unicode)) > 0 ) CWidth += This;
888
+ }
889
+ }
890
+
891
+ return CWidth;
892
+ }
893
+
894
+
895
+
896
+ ////////////////////////////////////////////////////////////////////////////////
897
+ // Public domain code to determine the width of a Unicode character //
898
+ ////////////////////////////////////////////////////////////////////////////////
899
+
900
+
901
+ /*
902
+ * This is an implementation of wcwidth() and wcswidth() as defined in
903
+ * "The Single UNIX Specification, Version 2, The Open Group, 1997"
904
+ * <http://www.UNIX-systems.org/online.html>
905
+ *
906
+ * Markus Kuhn -- 2000-02-08 -- public domain
907
+ */
908
+
909
+ //#include <wchar.h>
910
+
911
+ /* These functions define the column width of an ISO 10646 character
912
+ * as follows:
913
+ *
914
+ * - The null character (U+0000) has a column width of 0.
915
+ *
916
+ * - Other C0/C1 control characters and DEL will lead to a return
917
+ * value of -1.
918
+ *
919
+ * - Non-spacing and enclosing combining characters (general
920
+ * category code Mn or Me in the Unicode database) have a
921
+ * column width of 0.
922
+ *
923
+ * - Spacing characters in the East Asian Wide (W) or East Asian
924
+ * FullWidth (F) category as defined in Unicode Technical
925
+ * Report #11 have a column width of 2.
926
+ *
927
+ * - All remaining characters (including all printable
928
+ * ISO 8859-1 and WGL4 characters, Unicode control characters,
929
+ * etc.) have a column width of 1.
930
+ *
931
+ * This implementation assumes that wchar_t characters are encoded
932
+ * in ISO 10646.
933
+ */
934
+
935
+ int wcwidth(wchar_t ucs)
936
+ {
937
+ /* sorted list of non-overlapping intervals of non-spacing characters */
938
+ static const struct interval {
939
+ unsigned short first;
940
+ unsigned short last;
941
+ } combining[] = {
942
+ { 0x0300, 0x034E }, { 0x0360, 0x0362 }, { 0x0483, 0x0486 },
943
+ { 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 },
944
+ { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
945
+ { 0x05C4, 0x05C4 }, { 0x064B, 0x0655 }, { 0x0670, 0x0670 },
946
+ { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
947
+ { 0x0711, 0x0711 }, { 0x0730, 0x074A }, { 0x07A6, 0x07B0 },
948
+ { 0x0901, 0x0902 }, { 0x093C, 0x093C }, { 0x0941, 0x0948 },
949
+ { 0x094D, 0x094D }, { 0x0951, 0x0954 }, { 0x0962, 0x0963 },
950
+ { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 },
951
+ { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, { 0x0A02, 0x0A02 },
952
+ { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 },
953
+ { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 },
954
+ { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 },
955
+ { 0x0ACD, 0x0ACD }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
956
+ { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
957
+ { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
958
+ { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
959
+ { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBF, 0x0CBF },
960
+ { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, { 0x0D41, 0x0D43 },
961
+ { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 },
962
+ { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A },
963
+ { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 },
964
+ { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 },
965
+ { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 },
966
+ { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 },
967
+ { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 },
968
+ { 0x102D, 0x1030 }, { 0x1032, 0x1032 }, { 0x1036, 0x1037 },
969
+ { 0x1039, 0x1039 }, { 0x1058, 0x1059 }, { 0x17B7, 0x17BD },
970
+ { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x18A9, 0x18A9 },
971
+ { 0x20D0, 0x20E3 }, { 0x302A, 0x302F }, { 0x3099, 0x309A },
972
+ { 0xFB1E, 0xFB1E }, { 0xFE20, 0xFE23 }
973
+ };
974
+ int min = 0;
975
+ int max = sizeof(combining) / sizeof(struct interval) - 1;
976
+ int mid;
977
+
978
+ /* test for 8-bit control characters */
979
+ if (ucs == 0)
980
+ return 0;
981
+ if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
982
+ return -1;
983
+
984
+ /* first quick check for Latin-1 etc. characters */
985
+ if (ucs < combining[0].first)
986
+ return 1;
987
+
988
+ /* binary search in table of non-spacing characters */
989
+ while (max >= min) {
990
+ mid = (min + max) / 2;
991
+ if (combining[mid].last < ucs)
992
+ min = mid + 1;
993
+ else if (combining[mid].first > ucs)
994
+ max = mid - 1;
995
+ else if (combining[mid].first <= ucs && combining[mid].last >= ucs)
996
+ return 0;
997
+ }
998
+
999
+ /* if we arrive here, ucs is not a combining or C0/C1 control character */
1000
+
1001
+ /* fast test for majority of non-wide scripts */
1002
+ if (ucs < 0x1100)
1003
+ return 1;
1004
+
1005
+ return 1 +
1006
+ ((ucs >= 0x1100 && ucs <= 0x115f) || /* Hangul Jamo */
1007
+ (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a &&
1008
+ ucs != 0x303f) || /* CJK ... Yi */
1009
+ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
1010
+ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
1011
+ (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
1012
+ (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
1013
+ (ucs >= 0xffe0 && ucs <= 0xffe6));
1014
+ }
1015
+
1016
+
1017
+ int wcswidth(const wchar_t *pwcs, size_t n)
1018
+ {
1019
+ int w, width = 0;
1020
+
1021
+ for (;*pwcs && n-- > 0; pwcs++)
1022
+ if ((w = wcwidth(*pwcs)) < 0)
1023
+ return -1;
1024
+ else
1025
+ width += w;
1026
+
1027
+ return width;
1028
+ }
1029
+ #endif