1
/*===========================================================================
2
Copyright (C) 1995-2009 European Southern Observatory (ESO)
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License as
6
published by the Free Software Foundation; either version 2 of
7
the License, or (at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public
15
License along with this program; if not, write to the Free
16
Software Foundation, Inc., 675 Massachusetss Ave, Cambridge,
19
Correspondence concerning ESO-MIDAS should be addressed as follows:
20
Internet e-mail: midas@eso.org
21
Postal address: European Southern Observatory
22
Data Management Division
23
Karl-Schwarzschild-Strasse 2
24
D 85748 Garching bei Muenchen
26
===========================================================================*/
30
.AUTHOR Francois Ochsenbein [ESO]
32
.CATEGORY Basic string manipulation
36
Function names start with {\bf str} for case-sensitive functions,
37
with {\bf stu} for case-insensitive functions.
38
Declarations and corresponding macro definitions are in the header
40
The general features of all these functions are:
42
\item The first argument is always a pointer to the string to scan or modify;
43
\item All functions in this module return an integer, which is
45
\item either the length
46
\item or an index, with values 0 to (length-1) for success,
47
length for failure (mismatch).
48
It is then easy to test the found byte, as in the
53
printf("s contains a dot!");
55
\item or the result of a comparison
57
\item The function name is followed by an underscore `\_' when a table is
58
required as the last parameter. The usage of 256-byte tables for
59
span / scan / translate operations allow higher speed.
63
.VERSION 1.0 25-Nov-1985: Creation
65
.VERSION 2.0 26-Jan-1988: Prepared for Midas, on top of osc routines.
66
.VERSION 2.1 28-Mar-1989: Removed bug in stritem (if 2nd string is of length 0)
67
.VERSION 2.2 12-May-1989: Added strncopy.
68
.VERSION 2.3 16-Jun-1989: Check for null addresses
69
.VERSION 2.4 31-Jan-1990: Removed strid (now in str2). Cosmetic modifications
70
Added strloc1, strscan1
71
.VERSION 2.5 30-Mar-1990: Added strred (replace macro),
72
.VERSION 2.6 11-Sep-1990: Added strins (Insert)
75
----------------------------------------------------------------------------*/
80
#include <sys/types.h>
85
#define BITS_PER_CHAR 8
86
#define SIZE (1<<BITS_PER_CHAR)
88
static unsigned char ttable[SIZE];
89
static char argstr[2] = "x"; /* for stuloc / stuskip */
92
static unsigned char *cpt(table, tabl0)
94
.PURPOSE Copy table, inserting tabl0
95
.RETURNS Address of Copy
96
.REMARKS Copy because main_ascii is read-only ... can't just modify first byte
98
unsigned char *table; /* IN: Table to copy */
99
unsigned char tabl0; /* IN: Value of tabl[0] */
101
oscopy((char *)ttable, (char *)table, SIZE);
107
/*===========================================================================
109
*===========================================================================*/
110
int strcopy(dest, source)
112
.PURPOSE Copy strings, taking care of possible overlays.
113
.RETURNS Length of destination.
115
char *dest; /* OUT: destination string */
116
char *source; /* IN: source string */
121
len = strlen(source), oscopy(dest, source, len+1);
122
else *dest = '\0', len = 0;
127
int strncopy(dest, maxsize, source)
129
.PURPOSE Copy strings, taking care of possible overlays, but with max size.
130
(forbid any overfill)
131
.RETURNS Length of destination.
133
char *dest; /* OUT: destination string */
134
int maxsize; /* IN: Size of destination buffer (1+max.length) */
135
char *source; /* IN: source string */
146
len = strlen(source) + 1;
147
if (len > maxsize) len = maxsize;
149
p += oscopy(p, source, len);
158
int strfill(dest, len, filler)
160
.PURPOSE Fill a string with specified char, and terminates with EOS.
161
.RETURNS Length of destination.
163
char *dest; /* OUT: destination string */
164
int len; /* IN: Size of destination buffer */
165
int filler; /* IN: Character to be used for filling */
167
*(dest+oscfill(dest,len,filler)) = '\0';
171
/*===========================================================================
172
* Locate / Skip a char
173
*===========================================================================*/
176
.PURPOSE Locate the first occurence of character `c'
177
.RETURNS Index of `c' in str; length of str if `c' not found.
179
char *str; /* IN: string to scan */
180
char c; /* IN: char to locate */
191
.PURPOSE Locate the first occurence of character `c' --- but only if `c'
192
is not escaped by a backslash
193
.RETURNS Index of `c' in str; length of str if `c' not found.
195
char *str; /* IN: string to scan */
196
char c; /* IN: char to locate */
202
if (*p == '\\') { p++; continue; }
210
.PURPOSE Locate the last occurence of character `c'
211
.RETURNS Index of `c' in str; -1 if `c' not found.
213
char *str; /* IN: string to scan */
214
char c; /* IN: char to locate */
216
return(oscbloc(str,strlen(str),c));
219
/*===========================================================================*/
222
.PURPOSE Locate the first character that differs from `c'
223
.RETURNS Index of `c' in str; length of str if str is made only of `c's
225
char *str; /* IN: string to scan */
226
char c; /* IN: char to locate */
237
.PURPOSE Locate the last character that differs from `c'
238
.RETURNS Index of `c' in str; -1 if str is made only of `c's
240
char *str; /* IN: string to scan */
241
char c; /* IN: char to locate */
243
return(oscbskip(str, strlen(str), c));
246
/*===========================================================================*/
247
int stuset(table, list)
249
.PURPOSE Prepare table for scan / span operations: value of 1 for characters
250
in list, value 0 for other characters. Both upper and lower case
251
are inserted in table.
252
.RETURNS Length of list
254
unsigned char *table; /* OUT: Table with flagged characters */
255
char *list; /* IN: list of characters to flag */
259
oscfill((char *)table, SIZE, 0);
260
for (p=list; *p; p++)
261
{ *(table + *(unsigned char *)p) = 1;
262
*(table + (unsigned)tocase(*p)) = 1;
268
/*===========================================================================*/
269
int stuspans (str, list)
271
.PURPOSE Match as many as possible chars specified in list, case insensitive.
272
.RETURNS Index of first character which is not in list;
273
length of str if all characters are in list.
274
.REMARK To span e.g. alphabetic chars, use macro strspan(str, _ALPHA_)
276
char *str; /* IN: address of string to span */
277
char *list; /* IN: list of matching characters */
279
stuset(ttable, list);
280
return(oscspan((unsigned char *)str, (int) strlen(str), 1, ttable));
283
/*===========================================================================
284
* Scan / Span strings
285
*===========================================================================*/
287
int strset(table, list)
289
.PURPOSE Prepare table for scan / span operations: value of 1 for characters
290
in list, value 0 for other characters.
291
.RETURNS Length of list
293
unsigned char *table; /* OUT: Table [256] with flagged characters */
294
char *list; /* IN: list of characters to flag */
298
oscfill((char *)table, SIZE, 0);
299
for (p=list; *p; p++) *(table + *(unsigned char *)p) = 1;
304
/*===========================================================================*/
305
int strspan_ (str, mask, table)
307
.PURPOSE Match as many as possible of flagged (non-zero in table) chars.
308
.RETURNS Index of first character which is not flagged;
309
length of str if all characters are flagged.
310
.REMARKS Table can be created with strset.
311
If table[0] is not null, the result may be wrong.
313
char *str; /* IN: address of string to span */
314
unsigned char mask; /* IN: attribute mask */
315
unsigned char *table; /* IN: attribute table */
317
if (table[0] & mask) table = cpt(table, 0); /* EOS MUST end */
318
return(oscspan((unsigned char *)str, strlen(str), mask, table));
321
int strbspan_ (str, mask, table)
323
.PURPOSE Match as many as possible of flagged chars,
324
starting from end (backwards matching)
325
.RETURNS Index of first character which is not flagged (RIHT to LEFT); -1
326
if all characters are flagged.
327
.REMARKS Table can be created with strset
329
char *str; /* IN: address of string to span */
330
unsigned char mask; /* IN: attribute mask */
331
unsigned char *table; /* IN: attribute table */
333
return(oscbspan((unsigned char *)str, strlen(str), mask, table));
336
/*===========================================================================*/
337
int strspans (str, list)
339
.PURPOSE Match as many as possible chars specified in list.
340
.RETURNS Index of first character which is not in list;
341
length of str if all characters are in list.
343
char *str; /* IN: address of string to span */
344
char *list; /* IN: list of matching characters */
346
strset(ttable, list); /* ttable[0] is zero */
347
return(oscspan((unsigned char *)str, strlen(str), 1, ttable));
350
/*===========================================================================*/
351
int strbspans (str, list)
353
.PURPOSE Match as many as possible chars specified in list,
354
looking from the end of the string.
355
.RETURNS Index of last character which is not in list; -1 if
356
all characters are in list.
358
char *str; /* IN: address of string to span */
359
char *list; /* IN: list of matching characters */
361
strset(ttable, list);
362
return(oscbspan((unsigned char *)str, strlen(str), 1, ttable));
365
/*===========================================================================*/
366
int stubspans (str, list)
368
.PURPOSE Match as many as possible chars specified in list, case insensitive,
369
looking from the end of the string.
370
.RETURNS Index of last character which is not in list; -1 if
371
all characters are in list.
373
char *str; /* IN: address of string to span */
374
char *list; /* IN: list of matching characters */
376
stuset(ttable, list);
377
return(oscbspan((unsigned char *)str, strlen(str), 1, ttable));
381
/*===========================================================================*/
384
.PURPOSE Locate the first character that differs from `c', case insensitive.
385
.RETURNS Index of `c' in str; length of str if str is made only of `c's
387
char *str; /* IN: string to scan */
388
char c; /* IN: char to locate */
391
return(stuspans(str, argstr));
396
.PURPOSE Locate the last character that differs from `c', case insensitive.
397
.RETURNS Index of `c' in str; -1 if str is made only of `c's
399
char *str; /* IN: string to scan */
400
char c; /* IN: char to locate */
403
return(stubspans(str, argstr));
406
/*===========================================================================*/
407
int strscan_ (str, mask, table)
409
.PURPOSE Look for first flagged (non-zero in table) char.
410
.RETURNS Index of first flagged character; length of str if none was found.
411
.REMARKS Table can be created with strset
413
char *str; /* IN: address of string to span */
414
unsigned char mask; /* IN: attribute mask */
415
unsigned char *table; /* IN: attribute table */
417
if_not(table[0] & mask)
418
table = cpt(table, mask); /* EOS MUST end */
420
return(oscscan((unsigned char *)str, strlen(str), mask, table));
423
int strbscan_ (str, mask, table)
425
.PURPOSE Look for last flagged (non-zero in table) char.
426
.RETURNS Index of last flagged character, -1 if none was found.
427
.REMARKS Table can be created with strset
429
char *str; /* IN: address of string to span */
430
unsigned char mask; /* IN: attribute mask */
431
unsigned char *table; /* IN: attribute table */
433
return(oscbscan((unsigned char *)str, strlen(str), mask, table));
436
/*===========================================================================*/
437
int strscans (str, list)
439
.PURPOSE Look for first char specified in list.
440
.RETURNS Index of first character in str which is in list;
441
length of str if none was found.
442
.REMARK To scan e.g. alphabetic chars, use macro strscan(str, _ALPHA_)
444
char *str; /* IN: address of string to span */
445
char *list; /* IN: list of matching characters */
447
strset(ttable, list); ttable[0] = 1;
448
return(oscscan((unsigned char *)str, strlen(str), 1, ttable));
451
int strscan1 (str, list)
453
.PURPOSE Look for first char specified in list, only if not escaped
455
.RETURNS Index of first character in str which is in list;
456
length of str if none was found.
458
char *str; /* IN: address of string to span */
459
char *list; /* IN: list of matching characters */
463
strset(ttable, list); ttable[0] = 1; ttable['\\'] = 1;
466
{ p += oscscan((unsigned char *)p, strlen(p), 1, ttable);
467
if (*p != '\\') break;
473
/*===========================================================================*/
474
int stuscans (str, list)
476
.PURPOSE Look for first flagged (non-zero in table) char, case insensitive
477
.RETURNS Index of first character in str which is in list;
478
length of str if none was found.
480
char *str; /* IN: address of string to scan */
481
char *list; /* IN: list of matching characters */
483
stuset(ttable, list); ttable[0] = 1;
484
return(oscscan((unsigned char *)str, strlen(str), 1, ttable));
487
/*===========================================================================*/
488
int strbscans (str, list)
490
.PURPOSE Retrieve last char specified in list.
491
.RETURNS Index of last char in str which is in list, -1 if none was found.
493
char *str; /* IN: address of string to span */
494
char *list; /* IN: list of matching characters */
496
strset(ttable, list);
497
return(oscbscan((unsigned char *)str, strlen(str), 1, ttable));
500
/*===========================================================================*/
501
int stubscans (str, list)
503
.PURPOSE Retrieve last char specified in list, case insensitive.
504
.RETURNS Index of last char in str which is in list, -1 if none was found.
506
char *str; /* IN: address of string to scan */
507
char *list; /* IN: list of matching characters */
509
stuset(ttable, list);
510
return(oscbscan((unsigned char *)str, strlen(str), 1, ttable));
513
/*===========================================================================
515
*===========================================================================*/
518
/*++++++++++++++++++++++++
519
.PURPOSE Compare (or compute difference of) two strings.
520
.RETURNS A positive value if s1 > s2, zero if strings are identical,
521
a negative value if s1 < s2.
523
char *s1; /* IN: address of first string */
524
char *s2; /* IN: address of 2nd string */
526
register char *p, *q;
528
for (p=s1, q=s2; *p == *q; p++, q++)
534
/*===========================================================================*/
536
/*++++++++++++++++++++++++
537
.PURPOSE Compare (or compute difference of) two strings, case insensitive.
538
.RETURNS A positive value if s1 > s2, zero if strings are identical,
539
a negative value if s1 < s2.
541
char *s1; /* IN: address of first string */
542
char *s2; /* IN: address of 2nd string */
547
for (p=s1, q=s2; ; p++, q++)
548
{ cp = toupper(*p), cq = toupper(*q);
556
/*===========================================================================*/
558
/*++++++++++++++++++++++++
559
.PURPOSE Look for longest matching string.
560
.RETURNS The number of characters common to s1 and s2. If strings are identical,
561
the common length of both strings.
563
char *s1; /* IN: address of first string */
564
char *s2; /* IN: address of 2nd string */
566
register char *p, *q;
568
for (p=s1, q=s2; *p == *q; p++, q++)
574
/*===========================================================================*/
576
/*++++++++++++++++++++++++
577
.PURPOSE Look for longest matching string, case insensitive.
578
.RETURNS The number of characters common to s1 and s2. If strings are identical,
579
the common length of both strings.
581
char *s1; /* IN: address of first string */
582
char *s2; /* IN: address of 2nd string */
587
for (p=s1, q=s2; ; p++, q++)
588
{ cp = toupper(*p), cq = toupper(*q);
596
/*===========================================================================*/
597
int strindex( s1, s2)
598
/*++++++++++++++++++++++++
599
.PURPOSE Locates a substring within a string
600
.RETURNS Index within first string of second string;
601
length of the first string for mismatch.
602
.METHOD Use a scan on first char, then compare.
604
char *s1; /* IN: address of first string (source) */
605
char *s2; /* IN: address of 2nd string (object to find) */
610
if (s == NULL) return(strlen(s1));
615
/*===========================================================================*/
616
int stuindex( s1, s2)
617
/*++++++++++++++++++++++++
618
.PURPOSE Locates a substring within a string, case insensitive
619
.RETURNS Index within first string of second string;
620
length of the first string for mismatch.
621
.METHOD Use a scan on first char, then compare.
623
char *s1; /* IN: address of first string (source) */
624
char *s2; /* IN: address of 2nd string (object to find) */
630
if ((l2 = strlen(s2)) == 0) goto FIN;
631
oscfill((char *)ttable, sizeof(ttable), 0);
633
ttable[(int) *s2] = 1;
634
ttable[(unsigned)tocase(*s2)] = 1;
637
{ p1 += oscscan((unsigned char *)p1, strlen(p1), 1, ttable);
639
if (osccomp(p1, s2, l2) == 0) break;
645
/*===========================================================================*/
646
static int _item( s1, s2, sep)
647
/*++++++++++++++++++++++++
648
.PURPOSE Locates a substring within a string, which must be followed / preceded
649
by separator(s) characters
650
.RETURNS Index within first string of second string. The index
651
is the length of the first string for mismatch.
652
.METHOD Use strindex, then check preceding / following char.
654
char *s1; /* IN: address of first string (source) */
655
char *s2; /* IN: address of 2nd string (object to find) */
656
char *sep; /* IN: list of separators */
658
register char *p, *p1;
664
for (p = p1 = s1; ; p1 += i)
665
{ p1 += (*f)(p1, s2); /* Index of s2 in p1 */
666
if_not(*p1) break; /* Not Found... */
667
if (p1 > s1) /* Check preceding char */
669
if_not(sep[strloc(sep, *p)])
672
p = p1 + i; /* Check following char */
673
if_not(*p) break; /* Located at end : OK */
674
if (sep[strloc(sep, *p)]) /* Separator found */
681
/*===========================================================================*/
682
int stritem( s1, s2, sep)
683
/*++++++++++++++++++++++++
684
.PURPOSE Locates a substring within a string, which must be followed / preceded
685
by separator(s) characters
686
.RETURNS Index within first string of second string;
687
length of the first string for mismatch.
688
.METHOD Use strindex, then check preceding / following char.
690
char *s1; /* IN: address of first string (source) */
691
char *s2; /* IN: address of 2nd string (object to find) */
692
char *sep; /* IN: list of separators */
698
return(_item(s1,s2,sep));
701
/*===========================================================================*/
702
int stuitem( s1, s2, sep)
703
/*++++++++++++++++++++++++
704
.PURPOSE Locates a substring within a string, which must be followed / preceded
705
by separator(s) characters, case insensitive.
706
.RETURNS Index within first string of second string;
707
length of the first string for mismatch.
708
.METHOD Use stuindex, then check preceding / following char.
710
char *s1; /* IN: address of first string (source) */
711
char *s2; /* IN: address of 2nd string (object to find) */
712
char *sep; /* IN: list of separators */
718
return(_item(s1,s2,sep));
721
/*===========================================================================
723
*===========================================================================*/
725
int strsetr (table, s1, s2)
727
.PURPOSE Create a table for character translations.
728
.RETURNS Length of s1.
729
.REMARKS Characters in s1 without counterpart in s2 (i.e. s1 is longer
730
than s2) are replaced by a tilde (~).
732
unsigned char *table; /* OUT: translation table[256] */
733
char *s1; /* IN: list characters to translate */
734
char *s2; /* IN: list of translated characters */
736
register char *p, *q;
739
for (i=0; i<SIZE; i++) *(table + i) = i; /* Fill table */
740
for (p=s1, q=s2; *p; )
741
*(table + *(p++)) = (*q ? *(q++) : '~');
746
/*===========================================================================*/
747
int strtr_ (dest, source, table)
749
.PURPOSE Translate source into destination, according to translation table.
750
.RETURNS Length of source / destination
751
.REMARKS The translation table may be created by strsetr.
753
char *dest; /* OUT: the translated string */
754
char *source; /* IN: the string to translate */
755
unsigned char *table; /* IN: translation table */
757
return(osctr((unsigned char *)dest ,(unsigned char *)source, strlen(source)+1, table));
760
/*===========================================================================*/
761
int strtrs (dest, source, s1, s2)
763
.PURPOSE Translate source into destination, transforming characters in s1
764
into the corresponding character in s2.
765
.RETURNS Length of source / dest.
766
.REMARKS Characters in s1 without counterpart in s2 (i.e. s1 is longer
767
than s2) are replaced by a tilde (~).
768
The strings may overlap.
770
char *dest; /* OUT: the translated string */
771
char *source; /* IN: the string to translate */
772
char *s1; /* IN: list characters to translate */
773
char *s2; /* IN: list of translated characters */
777
strsetr(ttable, s1, s2);
778
len = strlen(source);
779
osctr((unsigned char *)dest, (unsigned char *)source, len+1, ttable);
783
/*===========================================================================
785
*===========================================================================*/
788
.PURPOSE Converts (in place) a string to lower case
789
.RETURNS Length of string
791
char *str; /* MOD: starting address */
795
for (p = str; *p; p++)
801
/*===========================================================================*/
804
.PURPOSE Converts (in place) a string to upper case
805
.RETURNS Length of string
807
char *str; /* MOD: starting address */
811
for (p = str; *p; p++)
817
/*===========================================================================*/
820
.PURPOSE Changes (in place) the case of a string, i.e. uppercase to lowercase
822
.RETURNS Length of string
824
char *str; /* MOD: starting address */
828
for (p = str; *p; p++)
834
/*===========================================================================
836
*===========================================================================*/
838
int strdel_ (str, mask, table)
840
.PURPOSE Delete all chars flagged in table
841
.RETURNS New Length of string
842
.REMARKS The string is EOS-terminated.
844
char *str; /* MOD: string to modify */
845
unsigned char mask; /* IN: Mask to use (ANDed with table) */
846
unsigned char *table; /* IN: table of flags */
848
register char *p, *q;
850
for ( p=str, q=p; *p; p++)
851
if (!(ischar_(*p, mask, table))) *(q++) = *p;
858
/*===========================================================================*/
859
int strred_ (str, mask, table)
861
.PURPOSE Reduces (in place) a string with suppression of redundant flagged
862
characters (e.g. spaces).
863
Leading and trailing spaces are also removed.
864
.RETURNS Length of modified (shorter) string.
866
char *str; /* MOD: string to modify */
867
unsigned char mask; /* IN: Mask to use (ANDed with table) */
868
unsigned char *table; /* IN: table of flags */
870
register char *p, *q;
871
char this_char, prec_char;
873
this_char = prec_char = mask; /* for a suppression of leading spaces */
875
for (p=str, q=p; *p; prec_char = this_char, p++)
876
{ this_char = ischar_(*p, mask, table);
877
if (prec_char && this_char) continue;
880
/* suppress last char if = fill */
881
if(prec_char && (q != str)) q--;
887
/*===========================================================================*/
890
.PURPOSE Reduces (in place) a string with suppression of redundant spaces.
891
Leading and trailing spaces are also removed.
892
.RETURNS Length of modified (shorter) string.
894
char *str; /* MOD: string to modify */
896
register char *p, *q;
897
char this_char, prec_char;
899
this_char = prec_char = ' '; /* for a suppression of leading spaces */
901
for (p=str, q=p; *p; prec_char = this_char, p++)
902
{ this_char = (isspace(*p) ? ' ' : *p);
903
if ((prec_char == ' ') && (this_char == ' ')) continue;
906
/* suppress last char if = fill */
907
if((prec_char == ' ') && (q != str)) q--;
913
/*===========================================================================*/
914
int strred1 ( str , escape )
916
.PURPOSE Reduces (in place) a string with suppression of `escape' char's,
917
e.g. if escape is \ replace \\ by \, \% by %, etc.
918
.RETURNS Length of reduced string.
919
.REMARKS First and last `escape' are also removed. This function can be
920
used e.g. to extract a string within quotes.
922
char *str; /* MOD: String to modify */
923
char escape; /* IN: escape char to be removed */
925
register char *p, *q;
927
for (p = str, q=p; *p; )
928
{ if (*p == escape) if (*(++p) == EOS) break;
937
/*===========================================================================
938
* Other string utilities
939
*===========================================================================*/
940
int strline_ ( str, lmax, mask, table)
942
.PURPOSE Look for the longest match of a line in a string without
943
cutting words; a word is made of chars surrounded by sep_char(s).
944
.RETURNS Returns the length of the best match.
945
.REMARKS The rightestmost space is ignored.
947
char *str; /* MOD: string to scan */
948
int lmax; /* IN: max length of a line */
949
unsigned char mask; /* IN: Mask to use (ANDed with table) */
950
unsigned char *table; /* IN: table of flags */
955
if_not(table[0] & mask)
956
table = cpt(table, mask); /* EOS MUST end */
959
{ len = oscscan((unsigned char *)p, lmax, mask, table);
960
if (((p-str)+len) > lmax) break;
962
p += oscspan((unsigned char *)p, lmax, mask, table); /* Don't span EOS! */
964
/* If no space was found, set to lmax */
965
if ((*p) && (p == str)) p = str + lmax;
970
/*===========================================================================*/
973
.PURPOSE Locate the first occurence of character `c', case insensitive.
974
.RETURNS Index of `c' or `C' in str; length of str if `c' not found.
976
char *str; /* IN: string to scan */
977
char c; /* IN: char to locate */
980
return(stuscans(str, argstr));
986
.PURPOSE Locate the last occurence of character `c', case insensitive.
987
.RETURNS Index of `c' or `C' in str; -1 if `c' not found.
989
char *str; /* IN: string to scan */
990
char c; /* IN: char to locate */
993
return(stubscans(str, argstr));