~ubuntu-branches/ubuntu/maverick/ploticus/maverick

« back to all changes in this revision

Viewing changes to src/glroutines.c

  • Committer: Bazaar Package Importer
  • Author(s): James W. Penny
  • Date: 2002-04-10 23:02:04 UTC
  • Revision ID: james.westby@ubuntu.com-20020410230204-64em4ns2f57c5u3l
Tags: 2.0.3-1
* The "That Tears it, Now You Have to Update Docs Package" Release.
* New upstream release (well, not so new :-( )   closes: Bug#137578
* Correct missing libpng2-dev in build-depends.  closes: Bug#142205
* Use correct syntax to:
* close URL type.                                closes: Bug#137577
* fix Architecture                               closes: Bug#141657
* close ITP                                      closes: Bug#132878

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GLROUTINES.C - general library routines
 
2
 * Copyright 1998-2002 Stephen C. Grubb  (ploticus.sourceforge.net) .
 
3
 * This code is covered under the GNU General Public License (GPL);
 
4
 * see the file ./Copyright for details. */
 
5
 
 
6
/* OS-specific #defines in rand() below. */
 
7
 
 
8
#include <stdio.h> 
 
9
#include <ctype.h>
 
10
#include <time.h>
 
11
#include <stdlib.h>
 
12
#define stricmp( s, t )         strcasecmp( s, t )
 
13
#define strnicmp( s, t, n )     strncasecmp( s, t, n )
 
14
 
 
15
#define DATAMAXLEN 256
 
16
#define NUMBER 0
 
17
#define ALPHA 1
 
18
 
 
19
static int encode();
 
20
static int getdecplaces();
 
21
static int wcmp();
 
22
 
 
23
static char Sep = ',';  /* separator character for lists */
 
24
static int domember();
 
25
static char     Gettok_buf[256];
 
26
static char starsym = '*';
 
27
static int Maxlen = 99999;
 
28
 
 
29
 
 
30
/* ================================= */
 
31
/* thanks to Markus Hoenicka for this more portable sysdate and systime code */
 
32
/* SYSDATE - get today's date */ 
 
33
 
 
34
GL_sysdate( mon, day, yr )
 
35
int     *mon, *day, *yr ;
 
36
{
 
37
time_t clock;
 
38
struct tm *ltime;
 
39
time(&clock);
 
40
ltime = localtime(&clock);
 
41
*mon = ltime->tm_mon + 1;
 
42
*day = ltime->tm_mday;
 
43
*yr = ltime->tm_year;
 
44
if( (*yr) >= 100 ) (*yr) = (*yr) % 100;  /* scg y2k 11/10/98 */
 
45
return( 0 );
 
46
}
 
47
 
 
48
/* ================================= */
 
49
/* SYSTIME - get current time */ 
 
50
GL_systime( hour, min, sec )
 
51
int     *hour, *min, *sec ;
 
52
{
 
53
time_t clock;
 
54
struct tm *ltime;
 
55
time(&clock);
 
56
ltime = localtime(&clock);
 
57
*hour = ltime->tm_hour;
 
58
*min = ltime->tm_min;
 
59
*sec = ltime->tm_sec;
 
60
return( 0 );
 
61
}
 
62
 
 
63
 
 
64
/* ===================================================== */
 
65
/* RAND returns a "random" number between 0.0 and 1.0 */
 
66
double GL_rand()
 
67
{
 
68
double r;
 
69
static int first = 1;
 
70
if( first ) {
 
71
        srand( getpid() % 1000 );
 
72
        first = 0;
 
73
        }
 
74
r = rand() / (double)(RAND_MAX);
 
75
if( r < 0.0 || r > 1.0 ) { printf( "%f: rand return out of range\n", r ); exit(1); }
 
76
return( r );
 
77
}
 
78
 
 
79
 
 
80
/* ============================================= */
 
81
/* GETOK - copied so that buffer size could be increased.. */
 
82
 
 
83
char *GL_getok( string, index )
 
84
char    *string;
 
85
int     *index;
 
86
{
 
87
int n;
 
88
while( GL_member( string[(*index)], " \t\n" ) ) (*index)++;
 
89
for( n=0;
 
90
        n <= 255 &&
 
91
        string[*index] != ' '  &&
 
92
        string[*index] != '\t'  &&
 
93
        string[*index] != '\n'  &&
 
94
        string[*index] != '\0'  ;
 
95
                Gettok_buf[n++] = string[(*index)++] )  ;
 
96
Gettok_buf[n] = '\0' ;
 
97
return( Gettok_buf );
 
98
}
 
99
 
 
100
/* ===================================================================== */
 
101
/* SMEMBER - look for s in list t (white-space delimited).  Case sensitive.
 
102
   If found return 1 else 0. */
 
103
 
 
104
GL_smember( s, t )
 
105
char s[], t[];
 
106
{
 
107
char tok[DATAMAXLEN+1], *GL_getok();
 
108
int i;
 
109
i = 0;
 
110
while( 1 ) {
 
111
        strcpy( tok, GL_getok( t, &i ) );
 
112
        if( tok[0] == '\0' ) break;
 
113
        if( strcmp( tok, s ) == 0 ) return( 1 );
 
114
        }
 
115
return( 0 );
 
116
}
 
117
/* ===================================================================== */
 
118
/* SMEMBERI - look for s in list t (white-space delimited).  Case insensitive.
 
119
   If found return 1 else 0. */
 
120
 
 
121
GL_smemberi( s, t )
 
122
char s[], t[];
 
123
{
 
124
char tok[DATAMAXLEN+1], *GL_getok();
 
125
int i;
 
126
i = 0;
 
127
while( 1 ) {
 
128
        strcpy( tok, GL_getok( t, &i ) );
 
129
        if( tok[0] == '\0' ) break;
 
130
        if( stricmp( tok, s ) == 0 ) return( 1 );
 
131
        }
 
132
return( 0 );
 
133
}
 
134
 
 
135
/* =========================================== */
 
136
/* SLMEMBER - Return 1 if str is matches any items in list.
 
137
        List is a space-delimited list of tokens.  The tokens in the
 
138
        list may contain ? or * wildcard characters.  The match is
 
139
        Case insensitive.
 
140
 
 
141
        scg 3-19-97
 
142
*/
 
143
GL_slmember( str, list )
 
144
char *str;
 
145
char *list;
 
146
{
 
147
char tok[100], *GL_getok();
 
148
int i;
 
149
i = 0;
 
150
while( 1 ) {
 
151
        strcpy( tok, GL_getok( list, &i ) );
 
152
        if( tok[0] == '\0' ) break;
 
153
        if( GL_wildcmp( str, tok, strlen(tok), 0 ) == 0 ) return( 1 );
 
154
        }
 
155
return( 0 );
 
156
}
 
157
 
 
158
 
 
159
/* ====================================================================== */
 
160
/* MEMBER - returns char position if character c is a member of string s, 
 
161
                0 otherwise. Char positions start with 1 for this purpose.  */
 
162
GL_member( c, s )
 
163
char c, s[];
 
164
{
 
165
int i, len;
 
166
for( i = 0, len = strlen( s ); i < len; i++ ) if( s[i] == c ) return( i+1 );
 
167
return( 0 );
 
168
}
 
169
 
 
170
 
 
171
/* ===================================================================== */
 
172
/* GOODNUM - checks a token to see if it is a legal number.  Returns 1 = yes  0 = no.
 
173
        'prec' is returned.. and is the precision of the number (position of decimal point).
 
174
 
 
175
        Number may contain unary + or -, and one decimal point.
 
176
        Leading and trailing whitespace are discarded before determining
 
177
        whether the case is a valid number or not.
 
178
*/
 
179
 
 
180
GL_goodnum( str, prec )
 
181
char *str;
 
182
int *prec;
 
183
{
 
184
int i, start, len, p, bad;
 
185
 
 
186
bad = 0; *prec = -1;
 
187
len = strlen( str );
 
188
 
 
189
/* find limit of trailing whitespace.. */
 
190
for( i = len-1; i >= 0; i-- ) if( !isspace( str[i] ) ) break;
 
191
len = i+1;
 
192
 
 
193
/* skip over leading whitespace.. */
 
194
for( i = 0; i < len; i++ ) if( !isspace( str[i] ) ) break;
 
195
start = i;
 
196
 
 
197
/* screen out degenerate cases.. */
 
198
if( len < 1 ) return( 0 ); /* degenerate case "" */
 
199
if( len-start == 1 && ( str[start] == '.' || str[start] == '+' || str[start] == '-' ) )
 
200
        return( 0 );       /* degenerate case; ".", "+", "-" */
 
201
 
 
202
/* check invididual characters.. */
 
203
for( p = start; p < len; p++ ) { 
 
204
        if( str[p] == '.' ) { 
 
205
                if( *prec == -1 ) *prec = p; 
 
206
                else bad=1; 
 
207
                }
 
208
        else if( p == start && ( str[p] == '-' || str[p] == '+' ) );
 
209
        else if( ! isdigit( str[p]) ) bad=1;
 
210
        }
 
211
 
 
212
/* return.. */
 
213
if( bad ) return( 0 );
 
214
else return( 1 );
 
215
}
 
216
 
 
217
/* =========================================== */
 
218
/* GETSEG - Get fields, which are delimited by any member of sepstring.
 
219
   Similar to GL_getchunk(); however
 
220
   Whereas GL_getchunk() skips over adjacent separators,
 
221
   this routine delimits on EACH separator character encountered,
 
222
   Also, separator character is ignored if preceded in inbuf by a backslash(\). 
 
223
 
 
224
   Returns 1 when end-of-line is reached and no token is being returned.
 
225
 
 
226
   SCG 12-2-96
 
227
*/
 
228
 
 
229
 
 
230
GL_getseg( rtn, inbuf, i, sep )
 
231
char rtn[];
 
232
char inbuf[];
 
233
int *i;
 
234
char *sep;
 
235
{
 
236
int n;
 
237
int escaping;
 
238
int eol;
 
239
 
 
240
n = 0;
 
241
rtn[0] = '\0';
 
242
escaping = 0;
 
243
eol = 0;
 
244
while( 1 ){
 
245
        if( inbuf[*i] == '\0' ) { 
 
246
                if( n == 0 ) eol = 1; 
 
247
                break; 
 
248
                }
 
249
        else if( GL_member( inbuf[*i], sep ) && !escaping ) { (*i)++; break; }
 
250
        else if( inbuf[*i] == '\\' && GL_member( inbuf[(*i)+1], sep ) ) { 
 
251
                escaping = 1; 
 
252
                (*i)++; 
 
253
                continue; 
 
254
                }
 
255
        else rtn[n++] = inbuf[(*i)++];
 
256
        if( n >= 511 ) break; /* 512 max */
 
257
        escaping = 0;
 
258
        }
 
259
rtn[n] = '\0' ;
 
260
return( eol );
 
261
}
 
262
 
 
263
/* ==================================================================== */
 
264
/* GETCHUNK - Get tokens, which are separated by any member of sepstring */
 
265
 
 
266
GL_getchunk( rtn, line, i, sepstring )
 
267
char rtn[];
 
268
char line[];
 
269
int *i;
 
270
char sepstring[];
 
271
{
 
272
 
 
273
int n;
 
274
 
 
275
while( GL_member( line[(*i)], sepstring ) ) (*i)++; 
 
276
n = 0;
 
277
rtn[0] = '\0';
 
278
while( 1 ){
 
279
        if( GL_member( line[*i], sepstring ) || line[*i] == '\0' ) break;
 
280
        else rtn[n++] = line[(*i)++];
 
281
        if( n >= (Maxlen-1) ) break;
 
282
        }
 
283
rtn[n] = '\0' ;
 
284
}
 
285
 
 
286
/* ==================================================================== */
 
287
/* SETMAXLEN - set maximum token length for GETSEG (future: others) */
 
288
 
 
289
GL_setmaxlen( maxlen )
 
290
int maxlen;
 
291
{
 
292
if( maxlen == 0 ) Maxlen = 99999;
 
293
else Maxlen = maxlen;
 
294
return( 0 );
 
295
}
 
296
 
 
297
 
 
298
/* ===================================================================== */
 
299
/* WILDCMP - compare two strings s1 and s2.  S2 may contain 
 
300
   wildcards (* and ?).
 
301
 
 
302
   Function returns 0 on a match;  < 0 if s1 < s2;   > 0 if s1 > s2
 
303
   Prints an error message and returns -999 on error.
 
304
 
 
305
   * wildcard limited to the following uses: *ppp; ppp*; pp*pp; *ppp*
 
306
   ? can be used anywhere.
 
307
 
 
308
   Double asterisks at beginning and end are also handled (means the
 
309
   same as single asterisk).
 
310
 
 
311
   scg 3-4-96 (written elsewhere)
 
312
 
 
313
 */
 
314
 
 
315
 
 
316
GL_wildcmp( char *s1, char *s2, int len, int casecare )
 
317
/* s1  = data value
 
318
   s2  = query value which can contain wildcards - not null terminated.
 
319
   len = length of s2
 
320
   casecare = 0 for case-insensitive, 1 for case-sensitive
 
321
 */
 
322
{
 
323
int i, nwc, wcp, stat, stat2;
 
324
 
 
325
 
 
326
if( len == 0 ) return( strlen( s1 ) );
 
327
else if( s2[0] == starsym ) {
 
328
        if( len == 1 ) return( 0 ); /* everything matches */
 
329
        }
 
330
else if( s2[0] == '?' ) ; /* can't tell yet */
 
331
else if( tolower( s1[0] ) < tolower( s2[0] ) ) return( -1 ); /* way off */
 
332
else if( tolower( s1[0] ) > tolower( s2[0] ) ) return( 1 );  /* way off */
 
333
 
 
334
/* strip off extraneous * at beginning and end.. */
 
335
if( s2[0] == starsym && s2[1] == starsym ) { s2 = &s2[1]; len--; }
 
336
if( s2[len-1] == starsym && s2[len-2] == starsym ) len--;
 
337
 
 
338
/* see if any wild cards were used.. */
 
339
nwc = 0;
 
340
for( i = 0; i < len; i++ ) if( s2[i] == starsym ) { nwc++; wcp = i; }
 
341
 
 
342
if( nwc < 1 ) {  /* straight match */
 
343
        if( strlen( s1 ) > len ) return( wcmp( s1, s2, strlen( s1 ), casecare));
 
344
        else return( wcmp( s1, s2, len, casecare ) ); 
 
345
        }
 
346
 
 
347
else if( nwc == 1 ) {                /* wildcard match */
 
348
        /* find beginning of what we need to compare */
 
349
        i = strlen( s1 ) - (len - (wcp+1) );
 
350
 
 
351
        /* case 1: wc at end.. */
 
352
        if( wcp == len-1 ) {
 
353
                return( wcmp( s1, s2, len-1, casecare ) );
 
354
                }
 
355
 
 
356
        /* case 2: wc at beginning.. */
 
357
        if( wcp == 0 ) {
 
358
                return( wcmp( &s1[i], &s2[ 1 ], len-1, casecare ) );
 
359
                }
 
360
 
 
361
        /* case 3: wc in middle.. */
 
362
        else    {
 
363
                int frontlen, backlen;
 
364
 
 
365
                frontlen = wcp;
 
366
 
 
367
                /* do front compare.. */
 
368
                stat = wcmp( s1, s2, frontlen, casecare ); 
 
369
                if( stat != 0 ) return( stat );
 
370
 
 
371
                backlen = strlen( s2 ) - (frontlen + 1);
 
372
                if( strlen( s1 )  < frontlen + backlen ) return( 1 );  /* fail if s1 too short */
 
373
 
 
374
                /* do back compare.. */
 
375
                stat = wcmp( &s1[ strlen( s1 ) - backlen ], &s2[ strlen( s2 ) - backlen ], backlen, casecare );
 
376
                return( stat );
 
377
 
 
378
                }
 
379
        }
 
380
 
 
381
else if( nwc == 2 ) {
 
382
        int stop;
 
383
        /* case 4: wc at beginning and end.. */
 
384
        if( wcp != (len-1) ) goto ERR;
 
385
        else if( s2[0] != starsym ) goto ERR;
 
386
        stop = ( strlen( s1 ) - len ) + 2;
 
387
        for( i = 0; i <= stop; i++ ) {
 
388
                if( wcmp( &s1[i], &s2[1], len-2, casecare ) == 0 ) return( 0 );
 
389
                }
 
390
 
 
391
        return( -1 );
 
392
        }
 
393
else    {
 
394
        ERR:
 
395
        fprintf( stderr, "Wild card match error (%s vs %s).\n", s1, s2 );
 
396
        return( -999 );
 
397
        }
 
398
}
 
399
 
 
400
/* WCMP - compare two strings.  S2 may contain ? wildcards which matches any
 
401
       single character.  Len is the # of characters to check.
 
402
 */
 
403
static int
 
404
wcmp( char *s1, char *s2, int len, int casecare )
 
405
{
 
406
int i;
 
407
for( i = 0; i < len; i++ ) {
 
408
        if( ! casecare ) {
 
409
                if( tolower(s1[i]) < tolower(s2[i]) && s2[i] != '?' ) 
 
410
                        return( -1 );
 
411
                else if( tolower(s1[i]) > tolower(s2[i]) && s2[i] != '?' ) 
 
412
                        return( 1 );
 
413
                }
 
414
        else    {
 
415
                if( s1[i] < s2[i] && s2[i] != '?' ) return( -1 );
 
416
                else if( s1[i] > s2[i] && s2[i] != '?' ) return( 1 );
 
417
                }
 
418
        }
 
419
return( 0 );
 
420
}
 
421
 
 
422
/* WILDCHAR - set the wildcard symbol to be used instead of '*' */
 
423
GL_wildchar( c )
 
424
char c;
 
425
{
 
426
starsym = c;
 
427
return( 0 );
 
428
}
 
429
 
 
430
/* ===================================================================== */
 
431
/* FUZZYMATCH - Do a 'fuzzy' match.  See if s1 is similar to s2.
 
432
 
 
433
   This routine may alter s1 and s2.
 
434
 
 
435
   A wildcard character '*' at the beginning or end of s2 indicates
 
436
   that a match can occur anywhere within s1 (eg. smith* would match
 
437
   smithington and *smith would match harrowsmith; *smith* would match
 
438
   both).  If there are no asterisks, lengths
 
439
   of the two strings must be similar.
 
440
 
 
441
   Degree changes the 'looseness' of the match.  
 
442
   5 = strict, 4 = medium-strict, 3 = medium 2= loose, 1 = very loose.
 
443
   
 
444
   Returns 1 on a match, 0 not. 
 
445
 
 
446
   SCG '94,'95
 
447
 */
 
448
 
 
449
GL_fuzzymatch( s1, s2, len2, degree )
 
450
char *s1; /* data value */
 
451
char *s2; /* query value */
 
452
int len2; /* length of s2 */
 
453
int degree; /* dgree of tightness */
 
454
{
 
455
int i, j, k, len1, pts;
 
456
int bestpts, score;
 
457
char c;
 
458
int openfront, openend, goal;
 
459
 
 
460
/* exact match.. no need to do more.. */
 
461
if( strcmp( s2, s1 ) ==0 ) return( 1 );
 
462
 
 
463
len1 = strlen( s1 );
 
464
 
 
465
/* see what type of match, open or closed */
 
466
if( s2[0] == '*' ) { openfront = 1; s2 = &s2[1]; len2--; }
 
467
else openfront = 0;
 
468
if( s2[ len2-1 ] == '*' ) { openend = 1; len2--; }
 
469
else openend = 0;
 
470
 
 
471
/* set goal */
 
472
if( len2 < 4 )goal = len2 * degree;
 
473
else if( len2 < 10 ) goal = (len2 -2) * degree;
 
474
else goal = (len2 -3) * degree;
 
475
 
 
476
 
 
477
/* reject disparate lengths if doing a closed match */
 
478
if( !openfront && !openend && len1 - len2 > 3 ) return( 0 );
 
479
 
 
480
/* truncate end of s1 if openended match */
 
481
if( openend && !openfront && len1 > len2+2 ) len1 = len2+2;
 
482
 
 
483
/* chop of front of s1 if openfronted match */
 
484
if( openfront && !openend && len1 > len2+2 ) s1 = &s1[ len1-(len2+2) ];
 
485
 
 
486
/* printf( "[%d-%d]", openfront, openend ); */
 
487
 
 
488
/* go thru s2.. */
 
489
score = 0;
 
490
for( i = 0; i < len2; i++ ) {
 
491
        c = s2[i];
 
492
 
 
493
        /* find each occurrence of c in s1.. */
 
494
        bestpts = 0;
 
495
        pts = 0;
 
496
        for( j = 0; j < len1; j++ ) {
 
497
 
 
498
                if( s1[j] == c ) {
 
499
 
 
500
                        /* check adjacent characters, count matches.. */
 
501
                        pts = 1;
 
502
 
 
503
                        if( i + j == 0 ) pts+=2; /* both 1st char */
 
504
                        
 
505
                        else /* go left.. */
 
506
                          for( k = 1; k <= 4; k++ ) {
 
507
                                if( j-k < 0 || i-k < 0 ) break;
 
508
                                else if( s1[j-k] == s2[i-k] ) pts++;
 
509
                                else break;
 
510
                                }
 
511
                        if( i == len2-1 && j == len1-1 )
 
512
                                pts+=2; /* both last char */
 
513
 
 
514
                        else /* go right.. */
 
515
                          for( k = 1; k <= 4; k++ ) {
 
516
                                if( j+k > len1-1 || i+k > len2-1 ) break;
 
517
                                else if( s1[j+k] == s2[i+k] ) pts++;
 
518
                                else break;
 
519
                                }
 
520
                        }
 
521
                if( pts > bestpts )bestpts = pts;
 
522
                }
 
523
        if( bestpts > 6 ) score += 6;
 
524
        else score += bestpts;
 
525
        /* printf( "[%c:%d]", c, bestpts ); */
 
526
        if( score > goal ) return( 1 ); /* optimize */
 
527
        }
 
528
/* printf( "<%s v. %s : %d>\n", s2, s1, score ); */
 
529
if( score > goal ) return( 1 );
 
530
else return( 0 );
 
531
}
 
532
 
 
533
 
 
534
/* ============================================= */
 
535
/* EXPAND_TABS Takes a string parameter 'in' and expands tabs into spaces, placing the
 
536
      result into parameter 'out'.  
 
537
 */
 
538
GL_expand_tabs( out, in )
 
539
char in[], out[];
 
540
{
 
541
int i, j, k, l, len;
 
542
 
 
543
out[0] = '\0';
 
544
k = 0;
 
545
for( i = 0, len = strlen( in ); i < len; i++ ) {
 
546
        if( in[i] == '\t' ) {
 
547
                j =  8 - ( k % 8 ); /* 1 to 8 spaces needed */
 
548
                for( l = 0; l < j; l++ ) out[k++] = ' ';
 
549
                }
 
550
        else out[k++] = in[i];
 
551
        }
 
552
out[k] = '\0';
 
553
}
 
554
 
 
555
 
 
556
/* ============================================= */
 
557
/* MAKE_UNIQUE_STRING - generate an identifier using date, time, and pid */
 
558
 
 
559
GL_make_unique_string( s, i )
 
560
char *s;
 
561
int i;  /* may be sent as an integer.. if 0 getpid() will be used.. */
 
562
{
 
563
int mon, day, yr, hr, min, sec, pid, a, b, c;
 
564
GL_sysdate( &mon, &day, &yr );
 
565
GL_systime( &hr, &min, &sec );
 
566
s[0] = encode( yr % 100 );
 
567
s[1] = encode( mon );
 
568
s[2] = encode( day );
 
569
s[3] = encode( hr );
 
570
s[4] = encode( min );
 
571
s[5] = encode( sec );
 
572
if( i == 0 ) pid = getpid();
 
573
else pid = i;
 
574
s[6] = encode( pid % 62 );
 
575
pid = pid / 62;
 
576
s[7] = encode( pid % 62 );
 
577
s[8] = encode( pid / 62 );
 
578
s[9] = '\0';
 
579
 
 
580
return( 0 );
 
581
}
 
582
 
 
583
/* encode - derive a character representation of a number */
 
584
static int encode( a )
 
585
int a;
 
586
{
 
587
if( a >= 0 && a <= 9 ) return( a + '0' );
 
588
else if( a > 35 ) return( (a-36) + 'A' ); /* A-Z    26 letters + 9 = 35 */
 
589
else if( a > 9 ) return( (a-10) + 'a' ); /* a-z */
 
590
else return( '0' );
 
591
}
 
592
 
 
593
/* ============================================= */
 
594
/* ADDMEMBER - append a new member to the end of a comma-delimited list */
 
595
GL_addmember( newmem, list )
 
596
char *newmem;
 
597
char *list;
 
598
{
 
599
if( list[0] == '\0' ) strcpy( list, newmem );
 
600
else    {
 
601
        strcat( list, "," );
 
602
        strcat( list, newmem );
 
603
        }
 
604
return( 0 );
 
605
}
 
606
 
 
607
/* ============================================= */
 
608
/* CONTAINS - if string s contains any of chars in clist, return position (1=first)
 
609
     of first occurance in list.  0 if not found at all.
 
610
     example: contains( "\"*'", "'hello'" )  -> 1
 
611
 */
 
612
GL_contains( clist, s )
 
613
char *clist, *s;
 
614
{
 
615
 
 
616
int i, len;
 
617
 
 
618
for( i = 0, len = strlen( s ); i < len; i++ ) {
 
619
        if( GL_member( s[i], clist )) return( i+1 );
 
620
        }
 
621
return( 0 );
 
622
}
 
623
/* ============================================= */
 
624
/* SUBST - change all occurances of s1 to s2, in t.
 
625
 
 
626
   Max length of t is 255.
 
627
   Returns 0 if successful, 1 if no occurance of s1 found. */
 
628
 
 
629
GL_substitute( s1, s2, t )
 
630
char *s1, *s2, *t;
 
631
{
 
632
char buf[255];
 
633
int i, j, len1, buflen, found;
 
634
 
 
635
len1 = strlen( s1 );
 
636
if( len1 < 1 ) return( 1 );
 
637
strcpy( buf, t );
 
638
buflen = strlen( buf );
 
639
if( buflen < 1 ) return( 1 );
 
640
 
 
641
found = 0;
 
642
j = 0;
 
643
for( i = 0; i < buflen; i++ ) {
 
644
/*      printf( "[%s|%s|%d]", &buf[i], s1, len1 ); */
 
645
 
 
646
        if( strncmp( &buf[i], s1, len1 )==0 ) {
 
647
                strcpy( &t[j], s2 );
 
648
                j += strlen( s2 );
 
649
                i += (len1 - 1);
 
650
                found = 1;
 
651
                }
 
652
        else t[j++] = buf[i];
 
653
        }
 
654
t[j] = '\0';
 
655
if( found ) return( 0 );
 
656
else return( 1 );
 
657
}
 
658
 
 
659
/* ============================================= */
 
660
/* CHANGECHARS - go through string s and if any characters in clist found, change
 
661
        the character to newchar */
 
662
GL_changechars( clist, s, newchar )
 
663
char *clist, *s, *newchar;
 
664
{
 
665
 
 
666
int i, len;
 
667
 
 
668
for( i = 0, len = strlen( s ); i < len; i++ ) {
 
669
        if( GL_member( s[i], clist )) s[i] = newchar[0];
 
670
        }
 
671
return( 0 );
 
672
}
 
673
 
 
674
/* ============================================= */
 
675
/* DELETECHARS - go through string s and if any characters in clist found, delete
 
676
        the character. */
 
677
GL_deletechars( clist, s )
 
678
char *clist, *s;
 
679
{
 
680
 
 
681
int i;
 
682
 
 
683
for( i = 0; ; ) {
 
684
        if( s[i] == '\0' ) break;
 
685
        if( GL_member( s[i], clist )) {
 
686
                strcpy( &s[i], &s[i+1] );
 
687
                continue;
 
688
                }
 
689
        else i++;
 
690
        }
 
691
return( 0 );
 
692
}
 
693
/* ======================================================================== */
 
694
/* SUBSTRING - 
 
695
   GL_substring( result, str, fromchar, nchar )
 
696
   char *result;   // substring is copied into this variable
 
697
   char *str;   // the original string
 
698
   int fromchar;   // starting point from which to take the substring
 
699
   int nchar;   // length of the substring
 
700
 
 
701
   In all cases the first char is 1, not 0.
 
702
 
 
703
   Two ways it can operate:
 
704
    If <fromchar> is greater than 0, the result will be the portion of <string>
 
705
        beginning at position <fromchar>, for a length of <nchar>, or until
 
706
        the end is reached.
 
707
    If <fromchar> is less than 0, and <nchar> is greater than 0:
 
708
        we will begin counting from the end of <string>, 
 
709
        leftward.  for (abs)<fromchar> characters.  Then, we will take the 
 
710
        substring beginning from that character 
 
711
        for a length of <nchar>, or until the end is reached.
 
712
        
 
713
    Examples: substring( result, "02001.fv02", 7, 4 )    -- result would be "fv02"
 
714
              substring( result, "02001.fv02", -4, 99 )   -- result would be "fv02"
 
715
*/
 
716
 
 
717
GL_substring( result, str, fromchar, nchar )
 
718
char *result;
 
719
char *str;
 
720
int fromchar;
 
721
int nchar;
 
722
{
 
723
int i, j;
 
724
int len;
 
725
 
 
726
len = strlen( str );
 
727
if( fromchar > 0 ) fromchar -= 1;
 
728
else if( fromchar < 0 ) fromchar += len;
 
729
 
 
730
for( i = fromchar, j = 0; i < fromchar + nchar; i++ ) { 
 
731
        if( i > len-1 ) break;
 
732
        result[j++] = str[i];
 
733
        }
 
734
result[j] = '\0';
 
735
return( 0 );
 
736
}
 
737
 
 
738
/* ===================================================================== */
 
739
/* VARSUB - given string s, find every occurance 
 
740
   of symbol (case-sensitive) and change it to value.  
 
741
    -Copies result into s.  
 
742
     -Returns number of times a substitution was made, 0 if none.
 
743
     -This routine is not sophisticated about delimiting the symbol;
 
744
      e.g. if s contains $NUMBER and varsub() is looking for $NUM it will find it.
 
745
*/
 
746
GL_varsub( s, symbol, value )
 
747
char *s, *symbol, *value;
 
748
{
 
749
int i, j, len, found;
 
750
int slen;
 
751
char rtnbuf[256];
 
752
 
 
753
len = strlen( symbol );
 
754
slen = strlen( s );
 
755
found = 0;
 
756
for( i = 0, j = 0; i < slen; i++, j++ ) {
 
757
        if( strncmp( &s[i], symbol, len )==0 ) {
 
758
                strcpy( &rtnbuf[j], value );
 
759
                j = strlen( rtnbuf ) - 1;
 
760
                i+= (len-1);
 
761
                found++;
 
762
                }
 
763
        else rtnbuf[j] = s[i]; 
 
764
        }
 
765
rtnbuf[j] = '\0';
 
766
strcpy( s, rtnbuf );
 
767
return( found );
 
768
}
 
769
 
 
770
 
 
771
 
 
772
/* ============================================= */
 
773
/* AUTOROUND - round the decimal portion a number reasonably based on its magnitude.
 
774
   val is the value, represented as a string.
 
775
   decoffset controls the precision of the rounded result as follows:
 
776
        If decoffset = 0 then nothing happens.  
 
777
        If decoffset = 1 then rounding will go to 1 additional decimal place.  
 
778
        decoffset = -1 then rounding will go to one less decimal place than normal.
 
779
 
 
780
   The rounded result is copied back into val.
 
781
 
 
782
   If val is non-numeric or a whole number then it is left unchanged.
 
783
*/
 
784
GL_autoround( val, decoffset )
 
785
char *val;
 
786
int decoffset; 
 
787
{
 
788
int precision, decplaces, stat;
 
789
char roundingfmt[50];
 
790
double g, atof();
 
791
 
 
792
stat = GL_goodnum( val, &precision );
 
793
if( stat && precision > 0 ) {
 
794
        g = atof( val );
 
795
        decplaces = getdecplaces( g );
 
796
        if( decplaces > -99 ) {
 
797
                if( decplaces < 0 ) decplaces = 0;
 
798
                sprintf( roundingfmt, "%%.%df", decplaces + decoffset );
 
799
                sprintf( val, roundingfmt, g );
 
800
                }
 
801
        }
 
802
return( 0 );
 
803
}
 
804
 
 
805
/* ============================================= */
 
806
/* AUTOROUNDF - variant of autoround(), takes val as a double, return value is character rep..*/
 
807
char *
 
808
GL_autoroundf( val, decoffset )
 
809
double val;
 
810
int decoffset;
 
811
{
 
812
int precision, decplaces, stat;
 
813
char roundingfmt[50];
 
814
static char result[50];
 
815
 
 
816
sprintf( result, "%g", val ); /* fallback */
 
817
decplaces = getdecplaces( val );
 
818
if( decplaces > -99 ) {
 
819
        if( decplaces < 0 ) decplaces = 0;
 
820
        sprintf( roundingfmt, "%%.%df", decplaces + decoffset );
 
821
        sprintf( result, roundingfmt, val );
 
822
        }
 
823
return( result );
 
824
}
 
825
 
 
826
static int getdecplaces( val )
 
827
double val;
 
828
{
 
829
int decplaces;
 
830
double g, fabs();
 
831
 
 
832
g = fabs( val );
 
833
decplaces = -99;
 
834
if( g >= 1000 ) decplaces = 0; 
 
835
else if( g >= 100 ) decplaces = 0; 
 
836
else if( g >= 10 ) decplaces = 1;
 
837
else if( g >= 1.0 ) decplaces = 2;
 
838
else if( g >= 0.1 ) decplaces = 3;
 
839
else if( g >= 0.01 ) decplaces = 4;
 
840
else if( g >= 0.001 ) decplaces = 5;
 
841
else if( g >= 0.0001 ) decplaces = 6;
 
842
 
 
843
return( decplaces );
 
844
}
 
845
 
 
846
/* ======================== */
 
847
/* FMOD  */
 
848
double fmod( a, b )
 
849
double a, b;
 
850
{
 
851
double x, y;
 
852
 
 
853
x = a / b;
 
854
y = (int) (x) * b;
 
855
return( a - y );
 
856
}
 
857
 
 
858
 
 
859
/* ======================================================================== */
 
860
/* RANGER - take a range specification of integers and return an enumeration of all members.
 
861
 *          Examples: "3-8" would return in list array: 3,4,5,6,7,8
 
862
 *                    "4,5,7-9,12-last" would return (for a 15 member list): 4,5,7,8,9,12,13,14,15
 
863
 *                    "4,5 7-9 12-last" would be equivalent to the above example.
 
864
 *                    "1-last" would return (for an 8 member list): 1,2,3,4,5,6,7,8
 
865
 *
 
866
 *          There may be no embedded spaces within the dash construct.
 
867
 */
 
868
 
 
869
GL_ranger( spec, list, n )
 
870
char *spec;
 
871
int *list;  /* array */
 
872
int *n;  /* in: size of list (max number of members)
 
873
            out: number of members in list that have been filled */
 
874
{
 
875
int i, ix, p, j, lo, hi;
 
876
char tok[80], histr[80];
 
877
 
 
878
/* parse spec.. */
 
879
ix = 0;
 
880
i = 0;
 
881
while( 1 ) {
 
882
        /* split up on commas or spaces */
 
883
        GL_getchunk( tok, spec, &ix, ", " );
 
884
        if( tok[0] == '\0'  ) break;
 
885
 
 
886
        if( GL_goodnum( tok, &p ) ) {
 
887
                list[i] = atoi( tok );
 
888
                i++;
 
889
                }
 
890
        else    {
 
891
                sscanf( tok, "%d-%s", &lo, histr );
 
892
                if( stricmp( histr, "last" )==0 ) hi = *n;
 
893
                else hi = atoi( histr );
 
894
                if( hi < lo ) {
 
895
                        fprintf( stderr, "bad range specification: %s\n", tok );
 
896
                        return( 1 );
 
897
                        }
 
898
                for( j = lo; j <= hi; j++ ) {
 
899
                        list[i] = j;
 
900
                        i++;
 
901
                        }
 
902
                }
 
903
        }
 
904
*n = i;
 
905
return( 0 );
 
906
}
 
907
 
 
908
 
 
909
/* ============================== */
 
910
/* CLOSE_TO - test two floating point numbers to see if
 
911
        they are within a small tolerance. */
 
912
 
 
913
GL_close_to( a, b, tol )
 
914
double a, b;
 
915
double tol;
 
916
{
 
917
if( a == b ) return( 1 );
 
918
else if( a > b && a - b < tol ) return( 1 );
 
919
else if( b > a && b - a < tol ) return( 1 );
 
920
else return( 0 );
 
921
}
 
922
 
 
923
 
 
924
/* ================================= */
 
925
/* CHECKSUM FUNCTIONS  */
 
926
 
 
927
/* CHECKDIG - returns the check digit for the number in aptr with length l.
 
928
        NOTE: when the check digit is computed to be 10 an `x' is returned.  
 
929
 
 
930
   This algorithm protects against interchanged digits.
 
931
*/
 
932
 
 
933
#define TEN     'x'
 
934
 
 
935
char GL_checkdig(aptr,l)
 
936
char *aptr;
 
937
int l;
 
938
{
 
939
int i,odds,evens,checkdigit;
 
940
        
 
941
odds = evens = 0;
 
942
i = 0;
 
943
 
 
944
while (i < l) {
 
945
        if (i % 2 == 0) { evens += (*(aptr+i) - '0'); }
 
946
        else { odds += (*(aptr+i) - '0'); }
 
947
        i++;
 
948
        }
 
949
checkdigit = (odds + (3 * evens)) % 11;
 
950
        
 
951
/* if the checkdigit is 10 then return the character to be used in place of ten */
 
952
if ( checkdigit == 10 ) return ( TEN );
 
953
else return(checkdigit+'0'); 
 
954
}
 
955
 
 
956
 
 
957
/* ------------ */
 
958
/* script entry point for checksum functions */
 
959
GL_checksum_functions( hash, name, arg, nargs, result, typ )
 
960
int hash;
 
961
char *name;
 
962
char *arg[];
 
963
int nargs;
 
964
char *result;
 
965
int *typ;
 
966
{
 
967
char *s;
 
968
 
 
969
if( hash == 2182 ) { /* $checksumvalid(s) -  validate s which is an integer containing a trailing check digit, 
 
970
                        using the algorithm in $ps/clibx/checkdig  */
 
971
        int i;
 
972
        i = GL_checkdig( arg[0], strlen( arg[0] ) -1 );
 
973
        if( i == arg[0][ strlen( arg[0] ) -1 ] ) sprintf( result, "1" );
 
974
        else sprintf( result, "0" );
 
975
        *typ = NUMBER;
 
976
        return( 0 );
 
977
        }
 
978
 
 
979
if( hash == 2412 ) { /* $checksumencode(i) - result is i with checksum digit appended. */
 
980
        long i, atol();
 
981
        char tmp[20];
 
982
        int cs;
 
983
        i = atol( arg[0] );
 
984
        sprintf( tmp, "%ld", i );
 
985
        cs = GL_checkdig( tmp, strlen( tmp ) );
 
986
        sprintf( result, "%s%c", tmp, cs );
 
987
        *typ = ALPHA;
 
988
        return( 0 );
 
989
        }
 
990
        
 
991
if( hash == 2155 ) { /* $checksumnext(s) take s which is a number including trailing checksum 
 
992
                        digit, increment number and recompute new checksum digit. */
 
993
        int cs;
 
994
        long i, atol();
 
995
        char tmp[20];
 
996
        s = arg[0];
 
997
        s[ strlen( s ) - 1 ] = '\0'; /* strip off existing checksum digit */
 
998
        i = atol( s );
 
999
        i++;
 
1000
        sprintf( tmp, "%ld", i );
 
1001
        cs = GL_checkdig( tmp, strlen( tmp ) );
 
1002
        sprintf( result, "%s%c", tmp, cs );
 
1003
        *typ = ALPHA;
 
1004
        return( 0 );
 
1005
        }
 
1006
 
 
1007
fprintf( stderr, "unrecognized function: %s\n", name ); /* not found */
 
1008
return( 195 );
 
1009
}
 
1010
 
 
1011
 
 
1012
/* ============================= */
 
1013
/* COMMONMEMBERS - compare two commalists and return number of members
 
1014
   that are in common.. */
 
1015
 
 
1016
GL_commonmembers( list1, list2, mode )
 
1017
char *list1;
 
1018
char *list2;
 
1019
int mode;       /* 0 = return a count; 1 = quit when one found */
 
1020
{
 
1021
int i, j, ii, ij, count;
 
1022
int len1, len2;
 
1023
char tok1[DATAMAXLEN+1], tok2[DATAMAXLEN+1];
 
1024
 
 
1025
count = 0;
 
1026
len1 = strlen( list1 );
 
1027
len2 = strlen( list2 );
 
1028
for( i = 0, ii = 0; ; i++ ) {
 
1029
        if( ii >= len1 ) break;
 
1030
        GL_getseg( tok1, list1, &ii, "," );
 
1031
        for( j = 0, ij = 0; ; j++ ) {
 
1032
                if( ij >= len2 ) break;
 
1033
                GL_getseg( tok2, list2, &ij, "," );
 
1034
                if( stricmp( tok1, tok2 )==0 ) {
 
1035
                        if( mode == 1 ) return( 1 );
 
1036
                        count++;
 
1037
                        }
 
1038
                }
 
1039
        }
 
1040
return( count );
 
1041
}
 
1042
 
 
1043
/* ==================================== */
 
1044
/* LISTMEMBER - see if s is in list (comma-delimited); 
 
1045
   if so return 1 and list position (first=1) and string position (first=0) */
 
1046
GL_listmember( s, list, memnum, pos )
 
1047
char *s;
 
1048
char *list;
 
1049
int *memnum;
 
1050
int *pos;
 
1051
{
 
1052
int ix, i, lastix, len;
 
1053
char tok[256];
 
1054
 
 
1055
*memnum = 0;
 
1056
ix = 0;
 
1057
len = strlen( list );
 
1058
lastix = 0;
 
1059
for( i = 1, ix = 0; ; i++ ) {
 
1060
        if( ix >= len ) break;
 
1061
        lastix = ix;
 
1062
        GL_getseg( tok, list, &ix, "," );
 
1063
        if( strcmp( tok, s )==0 ) {
 
1064
                *memnum = i;    
 
1065
                *pos = lastix;
 
1066
                return( 1 );
 
1067
                }
 
1068
        }
 
1069
return( 0 );
 
1070
}
 
1071
 
 
1072
/* ===================================== */
 
1073
/* GETCGIARG - get next arg from CGI REQUEST_URI string (escape constructs are converted) */
 
1074
GL_getcgiarg( arg, uri, pos, maxlen )
 
1075
char *arg, *uri;
 
1076
int *pos; /* current position */
 
1077
int maxlen; /* max size of string, including terminator */
 
1078
{
 
1079
int i, j;
 
1080
char hex[10];
 
1081
unsigned int val;
 
1082
 
 
1083
if( *pos == 0 ) {   /* scan to '?'.. */
 
1084
        for( i = 0; ; i++ ) {
 
1085
                if( uri[i] == '?' || uri[i] == '\0' ) {
 
1086
                        strncpy( arg, uri, i );
 
1087
                        arg[i] = '\0';
 
1088
                        if( uri[i] == '\0' ) *pos = i;
 
1089
                        else *pos = i+1;
 
1090
                        return( 0 );
 
1091
                        }
 
1092
                }
 
1093
        }
 
1094
else    {
 
1095
        for( i = *pos, j = 0; j < maxlen; i++ ) {
 
1096
                if( uri[i] == '&' || uri[i] == '\0' || j >= maxlen ) {
 
1097
                        arg[j] = '\0';
 
1098
                        if( uri[i] == '\0' ) *pos = i;
 
1099
                        else *pos = i+1;
 
1100
                        return( 0 );
 
1101
                        }
 
1102
                else if( uri[i] == '%' && isxdigit( uri[i+1] ) && isxdigit( uri[i+2] ) ) {
 
1103
                        sprintf( hex, "%c%c", uri[i+1], uri[i+2] );
 
1104
                        sscanf( hex, "%x", &val );
 
1105
                        arg[j++] = (char) val;
 
1106
                        i += 2;
 
1107
                        }
 
1108
                else arg[j++] = uri[i];
 
1109
                }
 
1110
        }
 
1111
return( 0 );
 
1112
}