/*===========================================================================* * * * sflstr.c - * * * * Copyright (c) 1991-2003 iMatix Corporation * * * * ------------------ GPL Licensed Source Code ------------------ * * iMatix makes this software available under the GNU General * * Public License (GPL) license for open source projects. For * * details of the GPL license please see www.gnu.org or read the * * file license.gpl provided in this package. * * * * 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 in the file 'license.gpl'; if * * not, write to the Free Software Foundation, Inc., 59 Temple * * Place - Suite 330, Boston, MA 02111-1307, USA. * * * * You can also license this software under iMatix's General Terms * * of Business (GTB) for commercial projects. If you have not * * explicitly licensed this software under the iMatix GTB you may * * only use it under the terms of the GNU General Public License. * * * * For more information, send an email to info@imatix.com. * * -------------------------------------------------------------- * *===========================================================================*/ #include "prelude.h" /* Universal header file */ #include "sfllist.h" /* Linked-list functions */ #include "sflmem.h" /* Memory handling functions */ #include "sflsymb.h" /* Symbol-table functions */ #include "sfltok.h" /* Token-handling functions */ #include "sflstr.h" /* Prototypes for functions */ /* Globals */ char *xstrcpy_file = ""; /* Source file calling xstrcpy */ word xstrcpy_line = 0; /* Source line for call */ /* ---------------------------------------------------------------------[<]- Function: strdupl Synopsis: Makes a duplicate of string, obtaining space with a call to malloc(). The allocated space is strlen (string) + 1 bytes long. The caller is responsible for freeing the space allocated by strdup when it is no longer needed. Returns a pointer to the allocated string, which holds a copy of the parameter string. Returns NULL if there was insufficient heap storage available to allocate the string, or if the original string was itself NULL. Use this function in place of the non-portable strdup() function. You may also want to use the more robust _mem_strdup () function. ---------------------------------------------------------------------[>]-*/ char * strdupl ( const char *string) { char *copy; size_t length; if (string) { length = strlen (string) + 1; copy = malloc (length); if (copy) strncpy (copy, string, length); } else copy = NULL; return (copy); } /* ---------------------------------------------------------------------[<]- Function: strfree Synopsis: Releases memory occupied by a string. Call this function only when you previously allocated the string using malloc or strdupl(). You pass the address of a char pointer; this function sets the pointer to NULL. This is a safety measure meant to make it safe to try to free non-allocated strings. In your code, initialise all such pointers to NULL. Returns the address of the modified pointer. ---------------------------------------------------------------------[>]-*/ char ** strfree ( char **string) { ASSERT (string); if (string && *string) { free (*string); *string = NULL; } return (string); } /* ---------------------------------------------------------------------[<]- Function: strskp Synopsis: Skips leading spaces in string, and returns a pointer to the first non-blank character. If this is a null, the end of the string was reached. ---------------------------------------------------------------------[>]-*/ char * strskp ( const char *string) { char *skip = (char *) string; ASSERT (string); while (*skip == ' ') skip++; return (skip); } /* ---------------------------------------------------------------------[<]- Function: strcset Synopsis: Sets all characters in string up to but not including the final null character to ch. Returns string. Use this function instead of the equivalent but non-portable strset() function. ---------------------------------------------------------------------[>]-*/ char * strcset ( char *string, char ch) { char *scan; ASSERT (string); scan = string; while (*scan) *scan++ = ch; return (string); } /* ---------------------------------------------------------------------[<]- Function: strpad Synopsis: Returns string of length characters, padding with ch or truncating if necessary. String must be at least length + 1 long. ---------------------------------------------------------------------[>]-*/ char * strpad ( char *string, char ch, int length) { int cursize; ASSERT (string); cursize = strlen (string); /* Get current length of string */ while (cursize < length) /* Pad until at desired length */ string [cursize++] = ch; string [cursize++] = '\0'; /* Add terminating null */ return (string); /* and return to caller */ } /* ---------------------------------------------------------------------[<]- Function: strlwc Synopsis: Converts all alphabetic characters in string to lowercase, stopping at the final null character. Returns string. If string is null, returns null. We do not call this function strlwr because that is already provided by some systems (but not by ANSI C). ---------------------------------------------------------------------[>]-*/ char * strlwc ( char *string) { char *scan; if (string) { scan = string; while (*scan) { *scan = (char) tolower (*scan); scan++; } } return (string); } /* ---------------------------------------------------------------------[<]- Function: strupc Synopsis: Converts all alphabetic characters in string to uppercase, stopping at the final null character. Returns string. If string is null, returns null. We do not call this function strupr because that is already provided by some systems (but not by ANSI C). ---------------------------------------------------------------------[>]-*/ char * strupc ( char *string) { char *scan; if (string) { scan = string; while (*scan) { *scan = (char) toupper (*scan); scan++; } } return (string); } /* ---------------------------------------------------------------------[<]- Function: strcrop Synopsis: Drops trailing whitespace from string by truncating string to the last non-whitespace character. Returns string. If string is null, returns null. ---------------------------------------------------------------------[>]-*/ char * strcrop ( char *string) { char *last; if (string) { last = string + strlen (string); while (last > string) { if (!isspace (*(last - 1))) break; last--; } *last = 0; } return (string); } /* ---------------------------------------------------------------------[<]- Function: stropen Synopsis: Inserts a character at string, and places a blank in the gap. If align is TRUE, makes room by reducing the size of the next gap of 2 or more spaces. If align is FALSE, extends the size of the string. Returns string. ---------------------------------------------------------------------[>]-*/ char * stropen ( char *string, Bool align) { char *gap; int length; ASSERT (string); length = strlen (string) + 1; /* By default, move string + NULL */ if (align) /* If align is TRUE, find gap */ { gap = strstr (string, " "); if (gap) length = (int) (gap - string); } memmove (string + 1, string, length); string [0] = ' '; /* Stick a space into string */ return (string); } /* ---------------------------------------------------------------------[<]- Function: strclose Synopsis: Removes the character at string, and shifts the remainder down by one. If align is TRUE, only shifts up to the next gap of 2 or more spaces. Returns string. ---------------------------------------------------------------------[>]-*/ char * strclose ( char *string, Bool align) { char *gap; int length; ASSERT (string); length = strlen (string); /* By default, move string + NULL */ if (align) { /* If align is TRUE, find gap */ gap = strstr (string, " "); if (gap && gap != string) length = (int) (gap - string); } memmove (string, string + 1, length); return (string); } /* ---------------------------------------------------------------------[<]- Function: strunique Synopsis: Reduces chains of some character to a single instances. For example: replace multiple spaces by one space. Returns string. ---------------------------------------------------------------------[>]-*/ char * strunique ( char *string, char unique) { char *from, *to; ASSERT (string); if (strnull (string)) return (string); /* Get rid of special cases */ from = string + 1; to = string; while (*from) { if (*from == unique && *to == unique) from++; else *++to = *from++; } *++to = '\0'; return (string); } /* ---------------------------------------------------------------------[<]- Function: strmatch Synopsis: Calculates a similarity index for the two strings. This is a value from 0 to 32767 with higher values indicating a closer match. The two strings are compared without regard for case. The algorithm was designed by Leif Svalgaard . ---------------------------------------------------------------------[>]-*/ int strmatch ( const char *string1, const char *string2) { static int name_weight [30] = { 20, 15, 13, 11, 10, 9, 8, 8, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4 }; int comp_index, name_index, start_of_string, longest_so_far, substring_contribution, substring_length, compare_length, longest_length, length_difference, name_length, char_index, similarity_index, similarity_weight; char cur_name_char; ASSERT (string1); ASSERT (string2); name_length = strlen (string1); compare_length = strlen (string2); if (name_length > compare_length) { length_difference = name_length - compare_length; longest_length = name_length; } else { length_difference = compare_length - name_length; longest_length = compare_length; } if (compare_length) { similarity_weight = 0; substring_contribution = 0; for (char_index = 0; char_index < name_length; char_index++) { start_of_string = char_index; cur_name_char = (char) tolower (string1 [char_index]); longest_so_far = 0; comp_index = 0; while (comp_index < compare_length) { while ((comp_index < compare_length) && (tolower (string2 [comp_index]) != cur_name_char)) comp_index++; substring_length = 0; name_index = start_of_string; while ((comp_index < compare_length) && (tolower (string2 [comp_index]) == tolower (string1 [name_index]))) { if (comp_index == name_index) substring_contribution++; comp_index++; if (name_index < name_length) { name_index++; substring_length++; } } substring_contribution += (substring_length + 1) * 3; if (longest_so_far < substring_length) longest_so_far = substring_length; } similarity_weight += (substring_contribution + longest_so_far + 1) * 2; similarity_weight /= name_length + 1; } similarity_index = (name_length < 30? name_weight [name_length]: 3) * longest_length; similarity_index /= 10; similarity_index += 2 * length_difference / longest_length; similarity_index = 100 * similarity_weight / similarity_index; } else similarity_index = 0; return (similarity_index); } /* ---------------------------------------------------------------------[<]- Function: strprefixed Synopsis: If string starts with specified prefix, returns TRUE. If string does not start with specified prefix, returns FALSE. ---------------------------------------------------------------------[>]-*/ Bool strprefixed ( const char *string, const char *prefix) { ASSERT (string); ASSERT (prefix); if (*string == *prefix /* Check that first letters match */ && strlen (string) >= strlen (prefix) && memcmp (string, prefix, strlen (prefix)) == 0) return (TRUE); else return (FALSE); } /* ---------------------------------------------------------------------[<]- Function: strprefix Synopsis: Looks for one of the delimiter characters in the string; if found, returns a string that contains the text up to that delimiter. If not found, returns NULL. The returned string can be zero or more characters long followed by a null byte. It is allocated using the mem_alloc() function; you should free it using mem_free() when finished. ---------------------------------------------------------------------[>]-*/ char * strprefix ( const char *string, const char *delims) { const char *nextch; char *token; int token_size; ASSERT (string); ASSERT (delims); for (nextch = string; *nextch; nextch++) { if (strchr (delims, *string)) /* Is next character a delimiter */ { token_size = (int) (nextch - string); token = mem_alloc (token_size + 1); if (token == NULL) return (NULL); /* Not enough memory - fail */ memcpy (token, string, token_size); token [token_size] = 0; return (token); } } return (NULL); } /* ---------------------------------------------------------------------[<]- Function: strdefix Synopsis: If string starts with specified prefix, returns pointer to character after prefix. Null character is not considered part of the prefix. If string does not start with specified prefix, returns NULL. ---------------------------------------------------------------------[>]-*/ char * strdefix ( const char *string, const char *prefix) { ASSERT (string); ASSERT (prefix); if (strlen (string) >= strlen (prefix) && memcmp (string, prefix, strlen (prefix)) == 0) return ((char *) string + strlen (prefix)); else return (NULL); } /* ---------------------------------------------------------------------[<]- Function: strhash Synopsis: Calculates a 32-bit hash value for the string. The string must end in a null. To use the result as a hash key, take the modulo over the hash table size. The algorithm was designed by Peter Weinberger. This version was adapted from Dr Dobb's Journal April 1996 page 26. Examples: int index; index = (int) strhash (name) % TABLE_SIZE; ---------------------------------------------------------------------[>]-*/ qbyte strhash ( const char *string) { qbyte high_bits, hash_value = 0; ASSERT (string); while (*string) { hash_value = (hash_value << 4) + *string++; if ((high_bits = hash_value & 0xF0000000L) != 0) hash_value ^= high_bits >> 24; hash_value &= ~high_bits; } return (hash_value); } /* ---------------------------------------------------------------------[<]- Function: strconvch Synopsis: Converts all instances of one character in a string to some other character. Returns string. Does nothing if the string is NULL. ---------------------------------------------------------------------[>]-*/ char * strconvch ( char *string, char from, char to) { char *scan; if (string) { scan = string; while (*scan) { if (*scan == from) *scan = to; scan++; } } return (string); } /* ---------------------------------------------------------------------[<]- Function: strconvchs Synopsis: Converts all instances of one character in a string to a string of one or more characters. Allocates a fresh string for the result. Does nothing if the supplier string is null. ---------------------------------------------------------------------[>]-*/ char * strconvchs ( char *string, char from, char *to) { size_t index, from_count; char *result; from_count = 0; for (index = 0; string [index]; index++) if (string [index] == from) from_count++; result = mem_alloc (strlen (string) + (strlen (to) - 1) * from_count + 1); index = 0; while (*string) { if (*string == from) { strcpy (result + index, to); index += strlen (to); } else result [index++] = *string; string++; } result [index] = '\0'; return (result); } /* ---------------------------------------------------------------------[<]- Function: xstrcat Synopsis: Concatenates multiple strings into a single result. Eg. xstrcat (buffer, "A", "B", NULL) stores "AB" in buffer. Returns dest. Append the string to any existing contents of dest. From DDJ Nov 1992 p. 155, with adaptions. ---------------------------------------------------------------------[>]-*/ char * xstrcat ( char *dest, const char *src, ...) { char *feedback = dest; va_list va; ASSERT (dest); while (*dest) /* Find end of dest string */ dest++; va_start (va, src); while (src) { while (*src) *dest++ = *src++; src = va_arg (va, char *); } *dest = '\0'; /* Append a null character */ va_end (va); return (feedback); } /* ---------------------------------------------------------------------[<]- Function: xstrcpy Synopsis: Concatenates multiple strings into a single result. Eg. xstrcpy (buffer, "A", "B", NULL) stores "AB" in buffer. Returns dest. Any existing contents of dest are cleared. If the dest buffer is NULL, allocates a new buffer with the required length and returns that. The buffer is allocated using mem_alloc(), and should eventually be freed using mem_free() or mem_strfree(). Returns NULL if there was too little memory to allocate the new string. We can't define macros with variable argument lists, so we pass the file and line number through two globals, xstrcpy_file and xstrcpy_line, which are reset to empty values after each call to xstrcpy. ---------------------------------------------------------------------[>]-*/ char * xstrcpy ( char *dest, const char *src, ...) { const char *src_ptr; va_list va; size_t dest_size; /* Size of concatenated strings */ /* Allocate new buffer if necessary */ if (dest == NULL) { va_start (va, src); /* Start variable args processing */ src_ptr = src; dest_size = 1; /* Allow for trailing null char */ while (src_ptr) { dest_size += strlen (src_ptr); src_ptr = va_arg (va, char *); } va_end (va); /* End variable args processing */ /* Allocate by going directly to mem_alloc_ function */ dest = mem_alloc_ (NULL, dest_size, xstrcpy_file, xstrcpy_line); xstrcpy_file = ""; xstrcpy_line = 0; if (dest == NULL) return (NULL); /* Not enough memory */ } /* Now copy strings into destination buffer */ va_start (va, src); /* Start variable args processing */ src_ptr = src; dest [0] = '\0'; while (src_ptr) { strcat (dest, src_ptr); src_ptr = va_arg (va, char *); } va_end (va); /* End variable args processing */ return (dest); } /* ---------------------------------------------------------------------[<]- Function: lexcmp Synopsis: Performs an unsigned comparison of two strings without regard to the case of any letters in the strings. Returns a value that is <_0 if string1 is less than string2 ==_0 if string1 is equal to string2 >_0 if string1 is greater than string2
---------------------------------------------------------------------[>]-*/ int lexcmp ( const char *string1, const char *string2) { int cmp; ASSERT (string1); ASSERT (string2); do { cmp = (byte) tolower (*string1) - (byte) tolower (*string2); } while (*string1++ && *string2++ && cmp == 0); return (cmp); } /* ---------------------------------------------------------------------[<]- Function: lexncmp Synopsis: Performs an unsigned comparison of two strings without regard to the case of specified number of letters in the strings. Returns a value that is <_0 if string1 is less than string2 ==_0 if string1 is equal to string2 >_0 if string1 is greater than string2
---------------------------------------------------------------------[>]-*/ int lexncmp ( const char *string1, const char *string2, const int count) { int cmp; char *end; ASSERT (string1); ASSERT (string2); end = (char *)string1 + count; do { cmp = (byte) tolower (*string1) - (byte) tolower (*string2); } while (*string1++ && *string2++ && cmp == 0 && string1 < end); return (cmp); } /* ---------------------------------------------------------------------[<]- Function: lexwcmp Synopsis: Compares two strings ignoring case, and allowing wildcards in the second string (the pattern). Two special characters are recognised in the pattern: '?' matches any character in the string, and '*' matches the remainder of the string. Returns a value that is: <_0 if string1 is less than pattern ==_0 if string1 is equal to pattern >_0 if string1 is greater than pattern
---------------------------------------------------------------------[>]-*/ int lexwcmp ( const char *string1, const char *pattern) { int cmp = 0; ASSERT (string1); ASSERT (pattern); do { if (*pattern != '?' && *pattern != '*') cmp = (byte) tolower (*string1) - (byte) tolower (*pattern); } while (*string1++ && *pattern++ && cmp == 0 && *pattern != '*'); return (cmp); } /* ---------------------------------------------------------------------[<]- Function: soundex Synopsis: Calculates the SOUNDEX code for the string. Returns the address of a static area that holds the code. This area is overwritten by each call to the soundex function. The SOUNDEX encoding converts letters to uppercase, and translates each letter according to this table: A0 B1 C2 D3 E0 F1 G2 H0 I0 J2 K2 L4 M5 N5 O0 P1 Q2 R6 S2 T3 U0 V1 W0 X2 Y0 Z2. Non-letters are ignored, letters that translate to zero, and multiple occurences of the same value are also ignored. This function always returns a 4-letter encoding: the first letter of the string followed by the first three significant digits. Examples: printf ("Soundex of %s = %s\n", argv [1], soundex (argv [1])); ---------------------------------------------------------------------[>]-*/ char * soundex ( const char *string) { ASSERT (string); return (soundexn (string, 4, FALSE)); } /* ---------------------------------------------------------------------[<]- Function: soundexn Synopsis: Calculates the SOUNDEX code for the string. Returns the address of a static area that holds the code. This area is overwritten by each call to the soundex function. The SOUNDEX encoding converts letters to uppercase, and translates each letter according to this table: A0 B1 C2 D3 E0 F1 G2 H0 I0 J2 K2 L4 M5 N5 O0 P1 Q2 R6 S2 T3 U0 V1 W0 X2 Y0 Z2. Non-letters are ignored, letters that translate to zero, and multiple occurences of the same value are also ignored. This function returns a N-letter encoding: the first letter of the string followed by the first N-1 significant digits. N may not be greater than SOUNDEX_MAX (100). If the fold argument is true, includes the first letter in the calculated digits, else starts with the second letter. ---------------------------------------------------------------------[>]-*/ char * soundexn ( const char *string, int size, Bool fold) { # define SOUNDEX_MAX 100 # define SOUNDEX_TABLE \ "00000000000000000000000000000000" \ "00000000000000000000000000000000" \ "00123012002245501262301020200000" \ "00123012002245501262301020200000" \ "00000000000000000000000000000000" \ "00000000000000000000000000000000" \ "00000000000000000000000000000000" \ "00000000000000000000000000000000" static char *soundex_table = SOUNDEX_TABLE, /* ASCII-SOUNDEX conversion */ soundex_code [SOUNDEX_MAX + 1]; /* Letter + 3 digits */ int index; char last_value = 0, this_value; ASSERT (string); ASSERT (size > 0 && size <= SOUNDEX_MAX); /* Initialise the soundex code to a string of zeroes */ memset (soundex_code, '0', size); soundex_code [size] = '\0'; soundex_code [0] = toupper (*string); last_value = fold? 0: soundex_table [(byte) *string]; index = 1; /* Store results at [index] */ while (*string) { this_value = soundex_table [(byte) *string++]; if (this_value == last_value /* Ignore doubles */ || this_value == '0') /* and 'quiet' letters */ { last_value = this_value; continue; } last_value = this_value; soundex_code [index++] = this_value; if (index == size) /* Up to size result characters */ break; } return (soundex_code); } /* ---------------------------------------------------------------------[<]- Function: strt2descr Synopsis: Converts a table of strings into a single block of memory. The input table consists of an array of null-terminated strings, terminated in a null pointer. Returns the address of a DESCR block defined as: "typedef struct {size_t size; byte *data} DESCR;". Allocates the descriptor block using the mem_alloc() function; you must free it using mem_free() when you are finished with it. The strings are packed into the descriptor data field, each terminated by a null byte. The final string is terminated by two nulls. The total size of the descriptor is descr-> size + sizeof (DESCR). Note that if you omit the last null pointer in the input table, you will probably get an addressing error. Returns NULL if there was insufficient memory to allocate the descriptor block. ---------------------------------------------------------------------[>]-*/ DESCR * strt2descr ( char **table) { DESCR *descr; /* Allocated descriptor */ char *descr_ptr; /* Pointer into block */ size_t descr_size; /* Size of table */ int string_nbr; /* Index into string table */ ASSERT (table); /* Calculate the size of the descriptor */ descr_size = 1; /* Allow for final null byte */ for (string_nbr = 0; table [string_nbr]; string_nbr++) descr_size += strlen (table [string_nbr]) + 1; /* Allocate a descriptor and fill it with the strings */ descr = mem_alloc (descr_size + sizeof (DESCR)); if (descr) { descr-> size = descr_size; descr-> data = (byte *) descr + sizeof (DESCR); descr_ptr = (char *) descr-> data; for (string_nbr = 0; table [string_nbr]; string_nbr++) { size_t descr_len = strlen (table [string_nbr]) + 1; strncpy (descr_ptr, table [string_nbr], descr_len); descr_ptr += descr_len; } *descr_ptr = '\0'; /* Add a null string */ } return (descr); } /* ---------------------------------------------------------------------[<]- Function: descr2strt Synopsis: Takes a descriptor prepared by strt2descr() and returns an array of strings pointers, terminated in a null pointer. The array is allocated using the mem_alloc() function. Each string is individually allocated. Thus, to free the string table you must call mem_free() for each entry in the table, except the last one, and then for the table. You can also call strtfree() to destroy the table in a single operation. Returns NULL if there was insufficient memory to allocate the table of strings. ---------------------------------------------------------------------[>]-*/ char ** descr2strt ( const DESCR *descr) { char **table; int string_count, string_nbr; /* Index into string table */ char *descr_ptr; /* Pointer into block */ ASSERT (descr); /* Count the number of strings in the table */ descr_ptr = (char *) descr-> data; string_count = 0; while (*descr_ptr) /* Loop until we hit null string */ { string_count++; descr_ptr += strlen (descr_ptr) + 1; } /* Allocate a table and fill it with the strings */ table = mem_alloc ((string_count + 1) * sizeof (char *)); if (table) { descr_ptr = (char *) descr-> data; for (string_nbr = 0; string_nbr < string_count; string_nbr++) { table [string_nbr] = mem_strdup (descr_ptr); descr_ptr += strlen (descr_ptr) + 1; } table [string_count] = NULL; /* Store final null pointer */ } return (table); } /* ---------------------------------------------------------------------[<]- Function: strtfree Synopsis: Releases a table of strings as created by descr2strt() or a similar function. If the argument is null, does nothing. ---------------------------------------------------------------------[>]-*/ void strtfree ( char **table) { int string_nbr; /* Index into string array */ if (table) { for (string_nbr = 0; table [string_nbr]; string_nbr++) mem_free (table [string_nbr]); mem_free (table); } } /* ---------------------------------------------------------------------[<]- Function: strcntch Synopsis: Returns number of instances of a character in a string. ---------------------------------------------------------------------[>]-*/ int strcntch (const char *string, char value) { int count = 0; ASSERT (string); while (*string) if (*string++ == value) count++; return (count); } /* ---------------------------------------------------------------------[<]- Function: strlookup Synopsis: Searches the specified lookup table, defined as an array of LOOKUP items, for the specified string key, and returns a lookup value. You are REQUIRED to terminate the table with a null key: if the key is not found in the table, returns the value for the last, null key. ---------------------------------------------------------------------[>]-*/ int strlookup (const LOOKUP *lookup, const char *key) { int index; ASSERT (lookup); ASSERT (key); for (index = 0; lookup [index].key; index++) if (streq (lookup [index].key, key)) break; return (lookup [index].value); } /* ---------------------------------------------------------------------[<]- Function: strreformat Synopsis: Reformats a string to fit within lines of the specified width. Prefixes each line with some optional text (included in the width). Allocates a fresh block of memory to contain the newly formatted line. ---------------------------------------------------------------------[>]-*/ char * strreformat (const char *source, size_t width, const char *prefix) { size_t total_size, /* Total size of buffer */ prefix_len, /* Size of prefix string */ token_len; /* Size of current token */ char **tokens, /* String broken into words */ *token, /* Current token */ *buffer, /* Target multiline buffer */ *bufptr; /* Next position in buffer */ int cur_width, /* Current line width incl. prefix */ token_nbr; /* Token number, 0..n */ ASSERT (source); if (source == NULL) return NULL; /* Ignore prefix if NULL */ if (prefix == NULL) prefix = ""; /* Calculate maximum size of resulting buffer, which is difficult to * predict accurately. We allow for 8 wasted characters on each line * plus the line ending. */ prefix_len = strlen (prefix); total_size = strlen (source) / (width - prefix_len) + 1; total_size = total_size * (width + 9); buffer = mem_alloc (total_size); tokens = tok_split (source); ASSERT (strlen (prefix) < width); ASSERT (total_size > tok_text_size (tokens)); cur_width = 0; bufptr = buffer; for (token_nbr = 0; tokens [token_nbr]; token_nbr++) { token = tokens [token_nbr]; token_len = strlen (token); /* First decide if next token will fit on line or not */ if (token_len + cur_width > width) { *bufptr++ = '\n'; /* Start new line */ cur_width = 0; } /* Put prefix at at start of line if necessary */ if (cur_width == 0) { /* If prefix would overflow buffer, we quit */ if ((bufptr - buffer) + prefix_len >= total_size) break; memcpy (bufptr, prefix, prefix_len); bufptr += prefix_len; cur_width = prefix_len; } /* If token would overflow buffer, we quit */ if ((bufptr - buffer) + token_len + 1 >= total_size) break; /* Now append token to line and add a space */ memcpy (bufptr, token, token_len); bufptr += token_len; cur_width += token_len + 1; *bufptr++ = ' '; } *bufptr = '\0'; /* Terminate the last line */ tok_free (tokens); return (buffer); } /* ---------------------------------------------------------------------[<]- Function: removechars Synopsis: Removes known chars from a string. Returns pointer to head of the buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * removechars ( char *strbuf, char *chrstorm) { char *offset; ASSERT (strbuf); ASSERT (chrstorm); offset = (char *)NULL; while (*strbuf) { offset = strpbrk (strbuf, chrstorm); if (offset) strcpy (offset, (offset + 1)); /* NO OVERRUN */ else break; } return strbuf; } /* ---------------------------------------------------------------------[<]- Function: replacechrswith Synopsis: Subsitutes known char(s)in a string with another. Returns pointer to head of the buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * replacechrswith ( char *strbuf, char *chrstorm, char chartorlcwith) { char *offset; ASSERT (strbuf); ASSERT (chrstorm); offset = (char *)NULL; while (*strbuf) { offset = strpbrk (strbuf, chrstorm); if (offset) { *(offset)= chartorlcwith; } else break; } return strbuf; } /* ---------------------------------------------------------------------[<]- Function: insertstring Synopsis: Inserts a string into another string. Returns a pointer to head of the buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * insertstring ( char *strbuf, char *chrstoins, int pos) { ASSERT (strbuf); ASSERT (chrstoins); memmove (((strbuf + pos) + strlen (chrstoins)), (strbuf + pos), (strlen ((strbuf + pos)) + 1)); memcpy ((strbuf + pos), chrstoins, strlen (chrstoins)); return strbuf; } /* ---------------------------------------------------------------------[<]- Function: insertchar Synopsis: Inserts a char into a string. Returns a pointer to head of the buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * insertchar ( char *strbuf, char chrtoins, int pos) { ASSERT (strbuf); memmove ((strbuf + pos)+ 1, (strbuf + pos), strlen ((strbuf + pos))+ 1); *(strbuf + pos)= chrtoins; return strbuf; } /* ---------------------------------------------------------------------[<]- Function: leftfill Synopsis: Pads a string to the left, to a know length, with the given char value. Returns a pointer to head of the buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * leftfill ( char *strbuf, char chrtofill, unsigned len) { ASSERT (strbuf); while (strlen (strbuf)< len) { insertchar (strbuf, chrtofill, 0); } return strbuf; } /* ---------------------------------------------------------------------[<]- Function: rightfill Synopsis: Pads a string to the right, to a known length, with the given char value. Returns a pointer to head of the buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * rightfill ( char *strbuf, char chrtofill, unsigned len) { ASSERT (strbuf); while (strlen (strbuf)< len) { insertchar (strbuf, chrtofill, strlen (strbuf)); } return strbuf; } /* ---------------------------------------------------------------------[<]- Function: trim Synopsis: Eats the whitespace's from the left and right side of a string. This function maintains a proper pointer head. Returns a pointer to head of the buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * trim ( char *strin) { ASSERT (strin); ltrim (strin); strcrop (strin); return strin; } /* ---------------------------------------------------------------------[<]- Function: ltrim Synopsis: Deletes leading white spaces in string, and returns a pointer to the first non-blank character. If this is a null, the end of the string was reached. ---------------------------------------------------------------------[>]-*/ char * ltrim ( char *string) { ASSERT (string); while (isspace(*string)) deletechar(string,0); return string; } /* ---------------------------------------------------------------------[<]- Function: searchreplace Synopsis: A case insensitive search and replace. Searches for all occurances of a string, and replaces it with another string. Returns a pointer to head of the buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * searchreplace ( char *strbuf, char *strtofnd, char *strtoins) { char *offset, *strbase; ASSERT (strbuf); ASSERT (strtofnd); ASSERT (strtoins); offset = strbase = (char *)NULL; while (*strbuf) { offset = stricstr (!offset ? strbuf : strbase, strtofnd); if (offset) { strbase = (offset + strlen (strtoins)); strcpy (offset, (offset + strlen (strtofnd))); memmove (offset + strlen (strtoins), offset, strlen (offset) + 1); memcpy (offset, strtoins, strlen (strtoins)); } else break; } return strbuf; } /* ---------------------------------------------------------------------[<]- Function: deletestring Synopsis: Deletes all occurances of one string, in another string. Returns a pointer to head of the buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * deletestring ( char *strbuf, char *strtodel, int ignorecase) { char *offset; ASSERT (strbuf); ASSERT (strtodel); offset = (char *)NULL; while (*strbuf) { if (!ignorecase) offset = stricstr (strbuf, strtodel); else offset = strstr (strbuf, strtodel); if (offset) { strcpy (offset, (offset + strlen (strtodel))); /* NO OVERRUN */ } else break; } return strbuf; } /* ---------------------------------------------------------------------[<]- Function: getstrfld Synopsis: Gets a sub-string from a formated string. nice strtok replacement. usage: char strarray[] = { "123,456,789,abc" }; char strretbuff[4]; getstrfld (strarray, 2, 0, ",", strretbuff); This would return the string "789" and place it also in strretbuff. Returns a NULL if fldno is out of range, else returns a pointer to head of the buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * getstrfld ( char *strbuf, int fldno, int ofset, char *sep, char *retstr) { char *offset, *strptr; int curfld; ASSERT (strbuf); ASSERT (sep); ASSERT (retstr); offset = strptr = (char *)NULL; curfld = 0; strbuf += ofset; while (*strbuf) { strptr = !offset ? strbuf : offset; offset = strpbrk ((!offset ? strbuf : offset), sep); if (offset) offset++; else if (curfld != fldno) { *retstr = (char)NULL; break; } if (curfld == fldno) { strncpy (retstr, strptr, (int)(!offset ? strlen (strptr)+ 1 : (int)(offset - strptr))); if (offset) retstr[offset - strptr - 1] = 0; break; } curfld++; } return retstr; } /* ---------------------------------------------------------------------[<]- Function: setstrfld Synopsis: Inserts a string into a fomated string. usage: char strsrray[26] = { "this is a test." }; setstrfld (strsrray, 2, 0, " ", "big "); result: this is a big test. Does nothing if fldno is out of range, else returns pointer to head of the buffer. Returns a pointer to head of the buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * setstrfld ( char *strbuf, int fldno, int ofset, char *sep, char *strtoins) { char *offset, *strptr, *strhead; int curfld; ASSERT (strbuf); ASSERT (sep); ASSERT (strtoins); offset = strptr = (char *)NULL; curfld = 0; strhead = strbuf; strbuf += ofset; while (*strbuf) { strptr = !offset ? strbuf : offset; offset = strpbrk ((!offset ? strbuf : offset), sep); if (offset) offset++; if (curfld == fldno) { insertstring (strptr, strtoins, (int)(!offset ? strlen (strptr): (int)(offset - strptr))); break; } curfld++; } return strhead; } /* ---------------------------------------------------------------------[<]- Function: getstrfldlen Synopsis: Get the length of as a field in a string. Used mainly for getting the len to malloc mem to call getstrfld with. Returns the length of the field. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ int getstrfldlen ( char *strbuf, int fldno, int ofset, char *sep) { char *offset, *strptr; int curfld, retlen = 0; ASSERT (strbuf); ASSERT (sep); offset = strptr = (char *)NULL; curfld = 0; strbuf += ofset; while (*strbuf) { strptr = !offset ? strbuf : offset; offset = strpbrk ((!offset ? strbuf : offset), sep); if (offset) offset++; else if (curfld != fldno) { retlen = 0; break; } if (curfld == fldno) { retlen = (int)(!offset ? strlen (strptr) + 1 : (int)(offset - strptr)); break; } curfld++; } return retlen; } /* ---------------------------------------------------------------------[<]- Function: findstrinfile Synopsis: Find's a string inside a text file and reads the line in and sets the file pointer to the beginning of that line. Assumes the line length to be <= 1024 bytes. Returns a pointer to head of the return buffer, and the file postion will be at the start of the found string. If the strretstr param is != NULL then strretstr will contain the line that the search string was found in. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * findstrinfile ( FILE *fp, char *strtofind, char *strretstr, int *iLnNo) { char strline[1025]; int nfnd = 0; long lfpos; ASSERT (fp); ASSERT (strtofind); ASSERT (strretstr); if (strretstr) *strretstr = 0; while (1) { lfpos = ftell (fp); fgets (strline, 1024, fp); trim (strline); if (!*strline) continue; if (iLnNo) (*iLnNo)++; if (stricstr (strline, strtofind)) { if (strretstr) { strcpy (strretstr, strline); } fseek (fp, lfpos, SEEK_SET); nfnd = 1; break; } if (feof (fp)) break; } if (strretstr) return strretstr; else return (char *)nfnd; } /* ---------------------------------------------------------------------[<]- Function: getequval Synopsis: get the everything on a line past a '='. Examples: char strtest[] = { "progpath=c:\sfl"); char strret[256]; getequval (strtest, strret); This would return: "c:\sfl". Returns a pointer to head of the return buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * getequval ( char *strline, char *strretstr) { char *stroffset; ASSERT (strline); ASSERT (strretstr); stroffset = strstr (strline, "="); if (stroffset) ltrim ((stroffset + 1)); else return (char *)NULL; return strcpy (strretstr, (stroffset && *(stroffset + 1))? (stroffset + 1): ""); } /* ---------------------------------------------------------------------[<]- Function: matchtable Synopsis: Function to compare a string with a set of strings. Examples: iret = matchtable (strname, "bill|william|billy", "|", IGNORECASE); If strname == "william", then matchtable would return 1. Returns >= 0 if match is found. a -1 if no match is found. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ int matchtable ( char *strbuf, char *strmatch, char *strsept, int ncase) { int nstate = -1, cnt = 0, icmpres; int ilen; char *strtemp; ASSERT (strbuf); ASSERT (strmatch); ASSERT (strsept); while (1) { ilen = getstrfldlen (strmatch, cnt, 0, strsept); strtemp = (char *) malloc (sizeof (char) * ilen + 1); ASSERT (strtemp); getstrfld (strmatch, cnt, 0, strsept, strtemp); if (*strtemp) { trim (strtemp); if (!ncase) { icmpres = lexcmp (strbuf, strtemp); } else { icmpres = strcmp (strbuf, strtemp); } if (!icmpres) { nstate = cnt; break; } else { if (!strcmp (strbuf, strtemp)) { nstate = cnt; break; } } } else { nstate = -1; break; } cnt++; free (strtemp); } return nstate; } /* ---------------------------------------------------------------------[<]- Function: stringreplace Synopsis: This function searches for known strings, and replaces them with another string. Examples: stringreplace (strfilename, "sqv|sqr,ruv|run,h_v|h"); This example would replace all occurences of sqv, with sqr, ruv with run and h_v with h. Returns pointer to head of the return buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * stringreplace ( char *strbuf, char *strpattern) { int ilen, ifld = 0; char *strsrch, *strrpl, *strpat; ASSERT (strbuf); ASSERT (strpattern); if (!strpattern) return strbuf; while (1) { ilen = getstrfldlen (strpattern, ifld, 0, ","); if (!ilen) break; strpat = (char *)malloc (ilen + 1); getstrfld (strpattern, ifld, 0, ",", strpat); ifld++; ilen = getstrfldlen (strpat, 0, 0, "|"); strsrch = (char *)malloc (ilen + 1); getstrfld (strpat, 0, 0, "|", strsrch); ilen = getstrfldlen (strpat, 1, 0, "|"); strrpl = (char *)malloc (ilen + 1); getstrfld (strpat, 1, 0, "|", strrpl); searchreplace (strbuf, strsrch, strrpl); free (strsrch); free (strrpl); free (strpat); } return strbuf; } /* ---------------------------------------------------------------------[<]- Function: wordwrapstr Synopsis: Function that does word wraping of a string at or less than iwid. Breaks up a string on word boundaries by placing '\n' in the string. Returns a pointer to head of the return buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * wordwrapstr ( char *strbuff, int iwid) { char *strtmp = strbuff; int icnt = 0; ASSERT (strbuff); replacechrswith (strbuff, "\n", ' '); while (*strtmp) { if ((int)strlen (strtmp) > (int)iwid) { icnt = iwid; while (*(strtmp + icnt)) { if (strchr (" .?;!,", *(strtmp + icnt))) { ltrim ((strtmp + icnt)); insertchar (strtmp, '\n', icnt); strtmp += icnt + 1; break; } icnt--; if (!icnt) { if (strchr (" .?;!,", *(strtmp + icnt))) { ltrim ((strtmp + iwid)); insertchar (strtmp, '\n', iwid); strtmp += iwid + 1; break; } } } } else break; } return strbuff; } /* ---------------------------------------------------------------------[<]- Function: stricstr Synopsis: A case insensitive strstr. Returns a pointer to head of the str1. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * stricstr ( const char *str1, const char *str2) { char *strtmp = (char *)str1; int iret = 1; ASSERT (str1); ASSERT (str2); while (*strtmp) { if (strlen (strtmp)>= strlen (str2)) { iret = lexncmp (strtmp, str2, strlen (str2)); } else { break; } if (!iret) { break; } strtmp++; } return !iret ? strtmp : (char *)NULL; } /* ---------------------------------------------------------------------[<]- Function: strtempcmp Synopsis: Compares a string to a template. Template chars and there functions: # or 9 = Number. A or _ = Alpha. @ = Alphanumeric \char = Literal. Char would be the literal to use. ie: "\%" - looks for a % in that postion Returns 0 if == to the template and 1 if != to the template. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ int strtempcmp ( const char *str1, const char *strPat) { int ires = 1; ASSERT (str1); ASSERT (strPat); while (*str1 && *strPat) { switch ((int)*strPat) { case '#': case '9': ires = isdigit ((int)*str1); break; case 'A': case '_': ires = isalpha ((int)*str1); break; case '@': ires = isalnum ((int)*str1); break; case ' ': ires = isspace ((int)*str1); break; case '\\': strPat++; if (*str1 != *strPat) { ires = 1; } break; default: break; } if (!ires) { break; } str1++; strPat++; } return ires ? 0 : 1; } /* ---------------------------------------------------------------------[<]- Function: istoken Synopsis: Eats strToEat from strBuff only if it begins with contents of strToEat, and returns a 0 or 1 to tell what it did. Examples: char strBuff[] = { "select * from mytbl;" }; int iWasToken; istoken (&strBuff, "SELECT", &iWasToken); On return here iWasToken would == 1, and strBuff would be: " * from mytbl;" If the token is not found, then strBuff will not be affected, and a 0 will be returned. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ int istoken ( char **strLine, const char *strtoken, int *iWasToken) { int iRet; char cChar; ASSERT (strLine); ASSERT (strtoken); ASSERT (iWasToken); iRet = lexncmp (*strLine, strtoken, strlen (strtoken)); if (!iRet) { cChar = *(*strLine + strlen (strtoken)); if (!isalpha ((int)cChar)&& cChar != '_') { iRet = *iWasToken = 1; strcpy (*strLine, (*strLine + strlen (strtoken))); } else iRet = *iWasToken = 0; } else iRet = *iWasToken = 0; return iRet; } /* ---------------------------------------------------------------------[<]- Function: eatstr Synopsis: Eats strToEat from strBuff only if it begins with contents of strToEat. Examples: char strBuff[] = { "select * from mytbl;" }; eatstr (&strBuff, "SELECT"); On return here strBuff would be: " * from mytbl;" If the token is not found, then strBuff will not be affected and a NULL char * will be returned, but any white spaces on the left of strBuff would be trimed. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * eatstr ( char **strBuff, char *strToEat) { int iWasToken; ASSERT (strBuff); ASSERT (strToEat); ltrim (*strBuff); istoken (strBuff, strToEat, &iWasToken); return iWasToken ? *strBuff : (char *)NULL; } /* ---------------------------------------------------------------------[<]- Function: eatstrpast Synopsis: Eats chars past first occurrence of one of the chars contained in strCharsToEatPast. Examples: char strBuff[] = { " , 456, 789" }; eatstrpast (&strBuff, ","); On return here strBuff would be: " 456, 789". Returns a pointer to head of the input buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * eatstrpast ( char **strBuff, char *strCharsToEatPast) { ASSERT (strBuff); ASSERT (strCharsToEatPast); ltrim (*strBuff); while (**strBuff && strchr (strCharsToEatPast, **strBuff)) deletechar (*strBuff, 0); return *strBuff; } /* ---------------------------------------------------------------------[<]- Function: movestrpast Synopsis: Eats chars past first occurrence of one of the chars contained in strCharsToEatPast. Examples: char strBuff[] = { "123, 456, 789" }; movestrpast (&strBuff, ","); On return here strBuff would be: " 456, 789". Returns a pointer to head of the input buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * movestrpast ( char **strBuff, char cCharToEatPast) { ASSERT (strBuff); ltrim (*strBuff); while (**strBuff && **strBuff != cCharToEatPast) deletechar (*strBuff, 0); if (**strBuff && **strBuff == cCharToEatPast) deletechar (*strBuff, 0); return *strBuff; } /* ---------------------------------------------------------------------[<]- Function: eatchar Synopsis: Trims white spaces and eats just past occurrence of cChar. If contents of cChar is not found then only white spaces are trimmed. Examples: char strBuff[] = { "('test', 5)" }; eatchar (&strBuff, '('); On return here strBuff would be: "'test', 5)". Returns a pointer to head of the input buffer. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ char * eatchar ( char **strBuff, char cChar) { ASSERT (strBuff); ltrim (*strBuff); if (**strBuff && **strBuff == cChar) deletechar (*strBuff, 0); return *strBuff; } /* ---------------------------------------------------------------------[<]- Function: isoneoftokens Synopsis: Eats strToEat from strBuff only if it begins with contents of strToEat, and returns a 0 or 1 to tell what it did. Returns 0 if nothing found, and >= 1 which is an index of the one found. Examples: char strBuff[] = { "select * from mytbl;" }; int iWasToken; isoneoftokens (&strBuff, "INSERT|SELECT|DELETE", "|", &iWasToken); On return here iWasToken would == 1, and strBuff would be: " * from mytbl;" and the return value would be 2. If the token is not found, then strBuff will not be affected, and a 0 will be returned. Submitted by Scott Beasley ---------------------------------------------------------------------[>]-*/ int isoneoftokens ( char **strbuf, char *strmat, char *strsep, int *iWasToken) { int nstate = 0, cnt = 0, icmpres; int iLen; char *strtemp, cChar; ASSERT (strbuf); ASSERT (strmat); ASSERT (strsep); ASSERT (iWasToken); while (1) { iLen = getstrfldlen (strmat, cnt, 0, strsep); strtemp = (char *) malloc (iLen + 1); getstrfld (strmat, cnt, 0, strsep, strtemp); if (*strtemp) { trim (strtemp); icmpres = lexncmp (*strbuf, strtemp, strlen (strtemp)); if (!icmpres) { cChar = *(*strbuf + strlen (strtemp)); if (!isalpha ((int)cChar)&& cChar != '_') { *iWasToken = cnt + 1; strcpy (*strbuf, (*strbuf + strlen (strtemp))); nstate = cnt + 1; } break; } else { if (!lexncmp (*strbuf, strtemp, strlen (strtemp))) { cChar = *(*strbuf + strlen (strtemp)); if (!isalpha ((int)cChar)&& cChar != '_') { *iWasToken = cnt + 1; strcpy (*strbuf, (*strbuf + strlen (strtemp))); nstate = cnt + 1; } break; } } } else { *iWasToken = 0; nstate = 0; break; } cnt++; free (strtemp); } return nstate; }