/* @(#)str1.c 17.1.1.1 (ES0-DMD) 01/25/02 17:36:55 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*+++++++++ .MODULE str1.c .AUTHOR Francois Ochsenbein [ESO] .LANGUAGE C .CATEGORY Basic string manipulation .COMMENTS \begin{TeX} Function names start with {\bf str} for case-sensitive functions, with {\bf stu} for case-insensitive functions. Declarations and corresponding macro definitions are in the header STR.H. The general features of all these functions are: \begin{itemize} \item The first argument is always a pointer to the string to scan or modify; \item All functions in this module return an integer, which is \begin{itemize} \item either the length \item or an index, with values 0 to (length-1) for success, length for failure (mismatch). It is then easy to test the found byte, as in the following example: \begin{verbatim} char s[80]; if (s[strloc(s,'.')]) printf("s contains a dot!"); \end{verbatim} \item or the result of a comparison \end{itemize} \item The function name is followed by an underscore `\_' when a table is required as the last parameter. The usage of 256-byte tables for span / scan / translate operations allow higher speed. \end{itemize} \end{TeX} .VERSION 1.0 25-Nov-1985: Creation .VERSION 2.0 26-Jan-1988: Prepared for Midas, on top of osc routines. .VERSION 2.1 28-Mar-1989: Removed bug in stritem (if 2nd string is of length 0) .VERSION 2.2 12-May-1989: Added strncopy. .VERSION 2.3 16-Jun-1989: Check for null addresses .VERSION 2.4 31-Jan-1990: Removed strid (now in str2). Cosmetic modifications Added strloc1, strscan1 .VERSION 2.5 30-Mar-1990: Added strred (replace macro), .VERSION 2.6 11-Sep-1990: Added strins (Insert) ----------------------------------------------------------------------------*/ #include #include #include #include #define BITS_PER_CHAR 8 #define SIZE (1< maxsize) len = maxsize; len--; p += oscopy(p, source, len); } *p = '\0'; } return(p-dest); } #if 0 int strcat(dest, source) /*+++++++ .PURPOSE Append source to dest .RETURNS Length of destination (strlen(dest)) ---------*/ char *dest; /* OUT: destination string */ char *source; /* IN: source string */ { register int len; register char *pd; pd = dest + strlen(dest); if (source) len = strlen(source), oscopy(dest, source, len+1); return(pd - dest); } int strncat(dest, maxsize, source) /*+++++++ .PURPOSE Append source to dest .RETURNS Length of destination (strlen(dest)) ---------*/ char *dest; /* OUT: destination string */ int maxsize; /* IN: Size of destination buffer (1+max.length) */ char *source; /* IN: source string */ { register int len; register char *pd; len = strlen(dest); len += strncopy (dest+len, maxsize-len, source); return(len); } #endif int strfill(dest, len, filler) /*+++++++ .PURPOSE Fill a string with specified char, and terminates with EOS. .RETURNS Length of destination. ---------*/ char *dest; /* OUT: destination string */ int len; /* IN: Size of destination buffer */ int filler; /* IN: Character to be used for filling */ { *(dest+oscfill(dest,len,filler)) = '\0'; return(len); } /*=========================================================================== * Locate / Skip a char *===========================================================================*/ int strloc(str, c) /*+++++++ .PURPOSE Locate the first occurence of character `c' .RETURNS Index of `c' in str; length of str if `c' not found. ---------*/ char *str; /* IN: string to scan */ char c; /* IN: char to locate */ { register char *p; for (p=str; *p; p++) if (*p == c) break; return(p-str); } int strloc1(str, c) /*+++++++ .PURPOSE Locate the first occurence of character `c' --- but only if `c' is not escaped by a backslash .RETURNS Index of `c' in str; length of str if `c' not found. ---------*/ char *str; /* IN: string to scan */ char c; /* IN: char to locate */ { register char *p; for (p=str; *p; p++) { if (*p == '\\') { p++; continue; } if (*p == c) break; } return(p-str); } int strbloc(str, c) /*+++++++ .PURPOSE Locate the last occurence of character `c' .RETURNS Index of `c' in str; -1 if `c' not found. ---------*/ char *str; /* IN: string to scan */ char c; /* IN: char to locate */ { return(oscbloc(str,strlen(str),c)); } /*===========================================================================*/ int stuloc(str, c) /*+++++++ .PURPOSE Locate the first occurence of character `c', case insensitive. .RETURNS Index of `c' or `C' in str; length of str if `c' not found. ---------*/ char *str; /* IN: string to scan */ char c; /* IN: char to locate */ { argstr[0] = c; return(stuscans(str, argstr)); } int stubloc(str, c) /*+++++++ .PURPOSE Locate the last occurence of character `c', case insensitive. .RETURNS Index of `c' or `C' in str; -1 if `c' not found. ---------*/ char *str; /* IN: string to scan */ char c; /* IN: char to locate */ { argstr[0] = c; return(stubscans(str, argstr)); } /*===========================================================================*/ int strskip(str, c) /*+++++++ .PURPOSE Locate the first character that differs from `c' .RETURNS Index of `c' in str; length of str if str is made only of `c's ---------*/ char *str; /* IN: string to scan */ char c; /* IN: char to locate */ { register char *p; for (p=str; *p; p++) if (*p != c) break; return(p-str); } int strbskip(str, c) /*+++++++ .PURPOSE Locate the last character that differs from `c' .RETURNS Index of `c' in str; -1 if str is made only of `c's ---------*/ char *str; /* IN: string to scan */ char c; /* IN: char to locate */ { return(oscbskip(str, strlen(str), c)); } /*===========================================================================*/ int stuskip(str, c) /*+++++++ .PURPOSE Locate the first character that differs from `c', case insensitive. .RETURNS Index of `c' in str; length of str if str is made only of `c's ---------*/ char *str; /* IN: string to scan */ char c; /* IN: char to locate */ { argstr[0] = c; return(stuspans(str, argstr)); } int stubskip(str, c) /*+++++++ .PURPOSE Locate the last character that differs from `c', case insensitive. .RETURNS Index of `c' in str; -1 if str is made only of `c's ---------*/ char *str; /* IN: string to scan */ char c; /* IN: char to locate */ { argstr[0] = c; return(stubspans(str, argstr)); } /*=========================================================================== * Scan / Span strings *===========================================================================*/ int strset(table, list) /*+++++++ .PURPOSE Prepare table for scan / span operations: value of 1 for characters in list, value 0 for other characters. .RETURNS Length of list ---------*/ unsigned char *table; /* OUT: Table [256] with flagged characters */ char *list; /* IN: list of characters to flag */ { register char *p; oscfill((char *)table, SIZE, 0); for (p=list; *p; p++) *(table + *(unsigned char *)p) = 1; return(p-list); } /*===========================================================================*/ int stuset(table, list) /*+++++++ .PURPOSE Prepare table for scan / span operations: value of 1 for characters in list, value 0 for other characters. Both upper and lower case are inserted in table. .RETURNS Length of list ---------*/ unsigned char *table; /* OUT: Table with flagged characters */ char *list; /* IN: list of characters to flag */ { register char *p; oscfill((char *)table, SIZE, 0); for (p=list; *p; p++) { *(table + *(unsigned char *)p) = 1; *(table + (unsigned)tocase(*p)) = 1; } return(p-list); } /*===========================================================================*/ int strspan_ (str, mask, table) /*+++++++ .PURPOSE Match as many as possible of flagged (non-zero in table) chars. .RETURNS Index of first character which is not flagged; length of str if all characters are flagged. .REMARKS Table can be created with strset. If table[0] is not null, the result may be wrong. ---------*/ char *str; /* IN: address of string to span */ unsigned char mask; /* IN: attribute mask */ unsigned char *table; /* IN: attribute table */ { if (table[0] & mask) table = cpt(table, 0); /* EOS MUST end */ return(oscspan(str, strlen(str), mask, table)); } int strbspan_ (str, mask, table) /*+++++++ .PURPOSE Match as many as possible of flagged chars, starting from end (backwards matching) .RETURNS Index of first character which is not flagged (RIHT to LEFT); -1 if all characters are flagged. .REMARKS Table can be created with strset ---------*/ char *str; /* IN: address of string to span */ unsigned char mask; /* IN: attribute mask */ unsigned char *table; /* IN: attribute table */ { return(oscbspan(str, strlen(str), mask, table)); } /*===========================================================================*/ int strspans (str, list) /*+++++++ .PURPOSE Match as many as possible chars specified in list. .RETURNS Index of first character which is not in list; length of str if all characters are in list. ---------*/ char *str; /* IN: address of string to span */ char *list; /* IN: list of matching characters */ { strset(ttable, list); /* ttable[0] is zero */ return(oscspan(str, strlen(str), 1, ttable)); } /*===========================================================================*/ int stuspans (str, list) /*+++++++ .PURPOSE Match as many as possible chars specified in list, case insensitive. .RETURNS Index of first character which is not in list; length of str if all characters are in list. .REMARK To span e.g. alphabetic chars, use macro strspan(str, _ALPHA_) ---------*/ char *str; /* IN: address of string to span */ char *list; /* IN: list of matching characters */ { stuset(ttable, list); return(oscspan(str, strlen(str), 1, ttable)); } /*===========================================================================*/ int strbspans (str, list) /*+++++++ .PURPOSE Match as many as possible chars specified in list, looking from the end of the string. .RETURNS Index of last character which is not in list; -1 if all characters are in list. ---------*/ char *str; /* IN: address of string to span */ char *list; /* IN: list of matching characters */ { strset(ttable, list); return(oscbspan(str, strlen(str), 1, ttable)); } /*===========================================================================*/ int stubspans (str, list) /*+++++++ .PURPOSE Match as many as possible chars specified in list, case insensitive, looking from the end of the string. .RETURNS Index of last character which is not in list; -1 if all characters are in list. ---------*/ char *str; /* IN: address of string to span */ char *list; /* IN: list of matching characters */ { stuset(ttable, list); return(oscbspan(str, strlen(str), 1, ttable)); } /*===========================================================================*/ int strscan_ (str, mask, table) /*+++++++ .PURPOSE Look for first flagged (non-zero in table) char. .RETURNS Index of first flagged character; length of str if none was found. .REMARKS Table can be created with strset ---------*/ char *str; /* IN: address of string to span */ unsigned char mask; /* IN: attribute mask */ unsigned char *table; /* IN: attribute table */ { if_not(table[0] & mask) table = cpt(table, mask); /* EOS MUST end */ return(oscscan(str, strlen(str), mask, table)); } int strbscan_ (str, mask, table) /*+++++++ .PURPOSE Look for last flagged (non-zero in table) char. .RETURNS Index of last flagged character, -1 if none was found. .REMARKS Table can be created with strset ---------*/ char *str; /* IN: address of string to span */ unsigned char mask; /* IN: attribute mask */ unsigned char *table; /* IN: attribute table */ { return(oscbscan(str, strlen(str), mask, table)); } /*===========================================================================*/ int strscans (str, list) /*+++++++ .PURPOSE Look for first char specified in list. .RETURNS Index of first character in str which is in list; length of str if none was found. .REMARK To scan e.g. alphabetic chars, use macro strscan(str, _ALPHA_) ---------*/ char *str; /* IN: address of string to span */ char *list; /* IN: list of matching characters */ { strset(ttable, list); ttable[0] = 1; return(oscscan(str, strlen(str), 1, ttable)); } int strscan1 (str, list) /*+++++++ .PURPOSE Look for first char specified in list, only if not escaped by a backslash .RETURNS Index of first character in str which is in list; length of str if none was found. ---------*/ char *str; /* IN: address of string to span */ char *list; /* IN: list of matching characters */ { char *p; strset(ttable, list); ttable[0] = 1; ttable['\\'] = 1; for (p = str; *p; ) { p += oscscan(p, strlen(p), 1, ttable); if (*p != '\\') break; p += 2; } return(p - str); } /*===========================================================================*/ int stuscans (str, list) /*+++++++ .PURPOSE Look for first flagged (non-zero in table) char, case insensitive .RETURNS Index of first character in str which is in list; length of str if none was found. ---------*/ char *str; /* IN: address of string to scan */ char *list; /* IN: list of matching characters */ { stuset(ttable, list); ttable[0] = 1; return(oscscan(str, strlen(str), 1, ttable)); } /*===========================================================================*/ int strbscans (str, list) /*+++++++ .PURPOSE Retrieve last char specified in list. .RETURNS Index of last char in str which is in list, -1 if none was found. ---------*/ char *str; /* IN: address of string to span */ char *list; /* IN: list of matching characters */ { strset(ttable, list); return(oscbscan(str, strlen(str), 1, ttable)); } /*===========================================================================*/ int stubscans (str, list) /*+++++++ .PURPOSE Retrieve last char specified in list, case insensitive. .RETURNS Index of last char in str which is in list, -1 if none was found. ---------*/ char *str; /* IN: address of string to scan */ char *list; /* IN: list of matching characters */ { stuset(ttable, list); return(oscbscan(str, strlen(str), 1, ttable)); } /*=========================================================================== * String Comparisons *===========================================================================*/ int strcomp(s1,s2) /*++++++++++++++++++++++++ .PURPOSE Compare (or compute difference of) two strings. .RETURNS A positive value if s1 > s2, zero if strings are identical, a negative value if s1 < s2. -----------*/ char *s1; /* IN: address of first string */ char *s2; /* IN: address of 2nd string */ { register char *p, *q; for (p=s1, q=s2; *p == *q; p++, q++) if (!(*p)) break; return(*p - *q); } /*===========================================================================*/ int stucomp(s1,s2) /*++++++++++++++++++++++++ .PURPOSE Compare (or compute difference of) two strings, case insensitive. .RETURNS A positive value if s1 > s2, zero if strings are identical, a negative value if s1 < s2. -----------*/ char *s1; /* IN: address of first string */ char *s2; /* IN: address of 2nd string */ { char *p, *q; char cp, cq; for (p=s1, q=s2; ; p++, q++) { cp = toupper(*p), cq = toupper(*q); if (cp != cq) break; if (!cp) break; } return(cp - cq); } /*===========================================================================*/ int strmatch(s1,s2) /*++++++++++++++++++++++++ .PURPOSE Look for longest matching string. .RETURNS The number of characters common to s1 and s2. If strings are identical, the common length of both strings. -----------*/ char *s1; /* IN: address of first string */ char *s2; /* IN: address of 2nd string */ { register char *p, *q; for (p=s1, q=s2; *p == *q; p++, q++) if (!(*p)) break; return(p - s1); } /*===========================================================================*/ int stumatch(s1,s2) /*++++++++++++++++++++++++ .PURPOSE Look for longest matching string, case insensitive. .RETURNS The number of characters common to s1 and s2. If strings are identical, the common length of both strings. -----------*/ char *s1; /* IN: address of first string */ char *s2; /* IN: address of 2nd string */ { char *p, *q; char cp, cq; for (p=s1, q=s2; ; p++, q++) { cp = toupper(*p), cq = toupper(*q); if (cp != cq) break; if (!cp) break; } return(p - s1); } /*===========================================================================*/ int strindex( s1, s2) /*++++++++++++++++++++++++ .PURPOSE Locates a substring within a string .RETURNS Index within first string of second string; length of the first string for mismatch. .METHOD Use a scan on first char, then compare. -----------*/ char *s1; /* IN: address of first string (source) */ char *s2; /* IN: address of 2nd string (object to find) */ { register char *s; s = strstr(s1,s2); if (s == NULL) return(strlen(s1)); else return(s-s1); } /*===========================================================================*/ int stuindex( s1, s2) /*++++++++++++++++++++++++ .PURPOSE Locates a substring within a string, case insensitive .RETURNS Index within first string of second string; length of the first string for mismatch. .METHOD Use a scan on first char, then compare. -----------*/ char *s1; /* IN: address of first string (source) */ char *s2; /* IN: address of 2nd string (object to find) */ { register char *p1; register int l2; p1 = s1; if ((l2 = strlen(s2)) == 0) goto FIN; oscfill((char *)ttable, sizeof(ttable), 0); ttable[0] = 1; ttable[*s2] = 1; ttable[(unsigned)tocase(*s2)] = 1; for (; *p1; p1++) { p1 += oscscan(p1, strlen(p1), 1, ttable); if (!(*p1)) break; if (osccomp(p1, s2, l2) == 0) break; } FIN: return(p1-s1); } /*===========================================================================*/ static int _item( s1, s2, sep) /*++++++++++++++++++++++++ .PURPOSE Locates a substring within a string, which must be followed / preceded by separator(s) characters .RETURNS Index within first string of second string. The index is the length of the first string for mismatch. .METHOD Use strindex, then check preceding / following char. -----------*/ char *s1; /* IN: address of first string (source) */ char *s2; /* IN: address of 2nd string (object to find) */ char *sep; /* IN: list of separators */ { register char *p, *p1; register int i; i = strlen(s2); if (i == 0) i = 1; for (p = p1 = s1; ; p1 += i) { p1 += (*f)(p1, s2); /* Index of s2 in p1 */ if_not(*p1) break; /* Not Found... */ if (p1 > s1) /* Check preceding char */ { p = p1-1; if_not(sep[strloc(sep, *p)]) continue; } p = p1 + i; /* Check following char */ if_not(*p) break; /* Located at end : OK */ if (sep[strloc(sep, *p)]) /* Separator found */ break; } return(p1-s1); } /*===========================================================================*/ int stritem( s1, s2, sep) /*++++++++++++++++++++++++ .PURPOSE Locates a substring within a string, which must be followed / preceded by separator(s) characters .RETURNS Index within first string of second string; length of the first string for mismatch. .METHOD Use strindex, then check preceding / following char. -----------*/ char *s1; /* IN: address of first string (source) */ char *s2; /* IN: address of 2nd string (object to find) */ char *sep; /* IN: list of separators */ { int strindex(); f = strindex; return(_item(s1,s2,sep)); } /*===========================================================================*/ int stuitem( s1, s2, sep) /*++++++++++++++++++++++++ .PURPOSE Locates a substring within a string, which must be followed / preceded by separator(s) characters, case insensitive. .RETURNS Index within first string of second string; length of the first string for mismatch. .METHOD Use stuindex, then check preceding / following char. -----------*/ char *s1; /* IN: address of first string (source) */ char *s2; /* IN: address of 2nd string (object to find) */ char *sep; /* IN: list of separators */ { int stuindex(); f = stuindex; return(_item(s1,s2,sep)); } /*=========================================================================== * String Conversions *===========================================================================*/ int strsetr (table, s1, s2) /*+++++++ .PURPOSE Create a table for character translations. .RETURNS Length of s1. .REMARKS Characters in s1 without counterpart in s2 (i.e. s1 is longer than s2) are replaced by a tilde (~). ---------*/ unsigned char *table; /* OUT: translation table[256] */ char *s1; /* IN: list characters to translate */ char *s2; /* IN: list of translated characters */ { register char *p, *q; register int i; for (i=0; i lmax) break; p += len; p += oscspan(p, lmax, mask, table); /* Don't span EOS! */ } /* If no space was found, set to lmax */ if ((*p) && (p == str)) p = str + lmax; return(p-str); }