diff options
Diffstat (limited to 'src/translators/btparse/names.c')
-rw-r--r-- | src/translators/btparse/names.c | 915 |
1 files changed, 915 insertions, 0 deletions
diff --git a/src/translators/btparse/names.c b/src/translators/btparse/names.c new file mode 100644 index 0000000..11c4bfd --- /dev/null +++ b/src/translators/btparse/names.c @@ -0,0 +1,915 @@ +/* ------------------------------------------------------------------------ +@NAME : names.c +@DESCRIPTION: Functions for dealing with BibTeX names and lists of names: + bt_split_list + bt_split_name +@GLOBALS : +@CALLS : +@CREATED : 1997/05/05, Greg Ward (as string_util.c) +@MODIFIED : 1997/05/14-05/16, GW: added all the code to split individual + names, renamed file to names.c +@VERSION : $Id: names.c,v 1.23 1999/11/29 01:13:10 greg Rel $ +@COPYRIGHT : Copyright (c) 1996-99 by Gregory P. Ward. All rights reserved. + + This file is part of the btparse library. This library 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. +-------------------------------------------------------------------------- */ + +/*#include "bt_config.h"*/ +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "btparse.h" +#include "prototypes.h" +#include "error.h" +#include "my_alloca.h" +/*#include "my_dmalloc.h"*/ +#include "bt_debug.h" + + +#define MAX_COMMAS 2 + +#define update_depth(s,offs,depth) \ +switch (s[offs]) \ +{ \ + case '{': depth++; break; \ + case '}': depth--; break; \ +} + +/* + * `name_loc' specifies where a name is found -- used for generating + * useful warning messages. `line' and `name_num' are both 1-based. + */ +typedef struct +{ + char * filename; + int line; + int name_num; +} name_loc; + + +GEN_PRIVATE_ERRFUNC (name_warning, + (name_loc * loc, const char * fmt, ...), + BTERR_CONTENT, loc->filename, loc->line, + "name", loc->name_num, fmt) + + +/* ------------------------------------------------------------------------ +@NAME : bt_split_list() +@INPUT : string - string to split up; whitespace must be collapsed + eg. by bt_postprocess_string() + delim - delimiter to use; must be lowercase and should be + free of whitespace (code requires that delimiters + in string be surrounded by whitespace) + filename - source of string (for warning messages) + line - 1-based line number into file (for warning messages) + description - what substrings are (eg. "name") (for warning + messages); if NULL will use "substring" +@OUTPUT : substrings (*substrings is allocated by bt_split_list() for you) +@RETURNS : number of substrings found +@DESCRIPTION: Splits a string using a fixed delimiter, in the BibTeX way: + * delimiters at beginning or end of string are ignored + * delimiters in string must be surrounded by whitespace + * case insensitive + * delimiters at non-zero brace depth are ignored + + The list of substrings is returned as *substrings, which + is an array of pointers into a duplicate of string. This + duplicate copy has been scribbled on such that there is + a nul byte at the end of every substring. You should + call bt_free_list() to free both the duplicate copy + of string and *substrings itself. Do *not* walk over + the array free()'ing the substrings yourself, as this is + invalid -- they were not malloc()'d! +@GLOBALS : +@CALLS : +@CALLERS : anyone (exported by library) +@CREATED : 1997/05/05, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +bt_stringlist * +bt_split_list (char * string, + char * delim, + char * filename, + int line, + char * description) +{ + int depth; /* brace depth */ + int i, j; /* offset into string and delim */ + int inword; /* flag telling if prev. char == ws */ + int string_len; + int delim_len; + int maxdiv; /* upper limit on no. of divisions */ + int maxoffs; /* max offset of delim in string */ + int numdiv; /* number of divisions */ + int * start; /* start of each division */ + int * stop; /* stop of each division */ + bt_stringlist * + list; /* structure to return */ + + if (string == NULL) + return NULL; + if (description == NULL) + description = "substring"; + + string_len = strlen (string); + delim_len = strlen (delim); + maxdiv = (string_len / delim_len) + 1; + maxoffs = string_len - delim_len + 1; + + /* + * This is a bit of a band-aid solution to the "split empty string" + * bug (formerly hit the internal_error() at the end of hte function). + * Still need a general "detect and fix unpreprocessed string" -- + * admittedly a different bug/misfeature. + */ + if (string_len == 0) + return NULL; + + start = (int *) alloca (maxdiv * sizeof (int)); + stop = (int *) alloca (maxdiv * sizeof (int)); + + list = (bt_stringlist *) malloc (sizeof (bt_stringlist)); + + depth = 0; + i = j = 0; + inword = 1; /* so leading delim ignored */ + numdiv = 0; + start[0] = 0; /* first substring @ start of string */ + + while (i < maxoffs) + { + /* does current char. in string match current char. in delim? */ + if (depth == 0 && !inword && tolower (string[i]) == delim[j]) + { + j++; i++; + + /* have we found an entire delim, followed by a space? */ + if (j == delim_len && string[i] == ' ') + { + + stop[numdiv] = i - delim_len - 1; + start[++numdiv] = ++i; + j = 0; + +#if DEBUG + printf ("found complete delim; i == %d, numdiv == %d: " + "stop[%d] == %d, start[%d] == %d\n", + i, numdiv, + numdiv-1, stop[numdiv-1], + numdiv, start[numdiv]); +#endif + } + } + + /* no match between string and delim, at non-zero depth, or in a word */ + else + { + update_depth (string, i, depth); + inword = (i < string_len) && (string[i] != ' '); + i++; + j = 0; + } + } + + stop[numdiv] = string_len; /* last substring ends just past eos */ + list->num_items = numdiv+1; + + + /* + * OK, now we know how many divisions there are and where they are -- + * so let's split that string up for real! + * + * list->items will be an array of pointers into a duplicate of + * `string'; we duplicate `string' so we can safely scribble on it and + * free() it later (in bt_free_list()). + */ + + list->items = (char **) malloc (list->num_items * sizeof (char *)); + list->string = strdup (string); + + for (i = 0; i < list->num_items; i++) + { + /* + * Possible cases: + * - stop < start is for empty elements, e.g. "and and" seen in + * input. (`start' for empty element will be the 'a' of the + * second 'and', and its stop will be the ' ' *before* the + * second 'and'.) + * - stop > start is for anything else between two and's (the usual) + * - stop == start should never happen if the loop above is correct + */ + + if (stop[i] > start[i]) /* the usual case */ + { + list->string[stop[i]] = 0; + list->items[i] = list->string+start[i]; + } + else if (stop[i] < start[i]) /* empty element */ + { + list->items[i] = NULL; + general_error (BTERR_CONTENT, filename, line, + description, i+1, "empty %s", description); + } + else /* should not happen! */ + { + internal_error ("stop == start for substring %d", i); + } + } + + return list; +/* return num_substrings; */ + +} /* bt_split_list () */ + + +/* ------------------------------------------------------------------------ +@NAME : bt_free_list() +@INPUT : list +@OUTPUT : +@RETURNS : +@DESCRIPTION: Frees the list of strings created by bt_split_list(). +@GLOBALS : +@CALLS : +@CALLERS : anyone (exported by library) +@CREATED : 1997/05/06, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +void bt_free_list (bt_stringlist *list) +{ + if (list && list->string) free (list->string); + if (list && list->items) free (list->items); + if (list) free (list); +} + + + +/* ---------------------------------------------------------------------- + * Stuff for splitting up a single name + */ + + +/* ------------------------------------------------------------------------ +@NAME : find_commas +@INPUT : name - string to search for commas + max_commas - maximum number of commas to allow (if more than + this number are seen, a warning is printed and + the excess commas are removed) +@OUTPUT : +@RETURNS : number of commas found +@DESCRIPTION: Counts and records positions of commas at brace-depth 0. + Modifies string in-place to remove whitespace around commas, + excess commas, and any trailing commas; warns on excess or + trailing commas. Excess commas are removed by replacing them + with space and calling bt_postprocess_string() to collapse + whitespace a second time; trailing commas are simply replaced + with (char) 0 to truncate the string. + + Assumes whitespace has been collapsed (ie. no space at + beginning or end of string, and all internal strings of + whitespace reduced to exactly one space). +@GLOBALS : +@CALLS : name_warning() (if too many commas, or commas at end) +@CALLERS : bt_split_name() +@CREATED : 1997/05/14, Greg Ward +@MODIFIED : +-------------------------------------------------------------------------- */ +static int +find_commas (name_loc * loc, char *name, int max_commas) +{ + int i, j; + int depth; + int num_commas; + int len; + boolean at_comma; + boolean warned; + + i = j = 0; + depth = 0; + num_commas = 0; + len = strlen (name); + warned = 0; + + /* First pass to check for and blank out excess commas */ + + for (i = 0; i < len; i++) + { + if (depth == 0 && name[i] == ',') + { + num_commas++; + if (num_commas > max_commas) + { + if (! warned) + { + name_warning (loc, "too many commas in name (removing extras)"); + warned = TRUE; + } + name[i] = ' '; + } + } + } + + /* + * If we blanked out a comma, better re-collapse whitespace. (This is + * a bit of a cop-out -- I could probably adjust i and j appropriately + * in the above loop to do the collapsing for me, but my brain + * hurt when I tried to think it through. Some other time, perhaps. + */ + + if (warned) + bt_postprocess_string (name, BTO_COLLAPSE); + + /* Now the real comma-finding loop (only if necessary) */ + + if (num_commas == 0) + return 0; + + num_commas = 0; + i = 0; + while (i < len) + { + at_comma = (depth == 0 && name[i] == ','); + if (at_comma) + { + while (j > 0 && name[j-1] == ' ') j--; + num_commas++; + } + + update_depth (name, i, depth); + if (i != j) + name[j] = name[i]; + + i++; j++; + if (at_comma) + { + while (i < len && name[i] == ' ') i++; + } + } /* while i */ + + if (i != j) name[j] = (char) 0; + j--; + + if (name[j] == ',') + { + name_warning (loc, "comma(s) at end of name (removing)"); + while (name[j] == ',') + { + name[j--] = (char) 0; + num_commas--; + } + } + + return num_commas; + +} /* find_commas() */ + + +/* ------------------------------------------------------------------------ +@NAME : find_tokens +@INPUT : name - string to tokenize (should be a private copy + that we're free to clobber and mangle) +@OUTPUT : comma_token- number of token immediately preceding each comma + (caller must allocate with at least one element + per comma in `name') +@RETURNS : newly-allocated bt_stringlist structure +@DESCRIPTION: Finds tokens in a string; delimiter is space or comma at + brace-depth zero. Assumes whitespace has been collapsed + and find_commas has been run on the string to remove + whitespace around commas and any trailing commas. + + The bt_stringlist structure returned can (and should) be + freed with bt_free_list(). +@GLOBALS : +@CALLS : +@CALLERS : bt_split_name() +@CREATED : 1997/05/14, Greg Ward +@MODIFIED : +-------------------------------------------------------------------------- */ +static bt_stringlist * +find_tokens (char * name, + int * comma_token) +{ + int i; /* index into name */ + int num_tok; + int in_boundary; /* previous char was ' ' or ',' */ + int cur_comma; /* index into comma_token */ + int len; + int depth; + bt_stringlist * + tokens; + + i = 0; + in_boundary = 1; /* so first char will start a token */ + cur_comma = 0; + len = strlen (name); + depth = 0; + + tokens = (bt_stringlist *) malloc (sizeof (bt_stringlist)); + /* tokens->string = name ? strdup (name) : NULL; */ + tokens->string = name; + num_tok = 0; + tokens->items = NULL; + + if (len == 0) /* empty string? */ + return tokens; /* return empty token list */ + + tokens->items = (char **) malloc (sizeof (char *) * len); + + while (i < len) + { + if (depth == 0 && in_boundary) /* at start of a new token */ + { + tokens->items[num_tok++] = name+i; + } + + if (depth == 0 && (name[i] == ' ' || name[i] == ',')) + { + /* if we're at a comma, record the token preceding the comma */ + + if (name[i] == ',') + { + comma_token[cur_comma++] = num_tok-1; + } + + /* + * if already in a boundary zone, we have an empty token + * (caused by multiple consecutive commas) + */ + if (in_boundary) + { + tokens->items[num_tok-1] = NULL; + } + num_tok--; + + /* in any case, mark the end of one token and prepare for the + * start of the next + */ + name[i] = (char) 0; + in_boundary = 1; + } + else + { + in_boundary = 0; /* inside a token */ + } + + update_depth (name, i, depth); + i++; + + } /* while i */ + + tokens->num_items = num_tok; + return tokens; + +} /* find_tokens() */ + + +/* ------------------------------------------------------------------------ +@NAME : find_lc_tokens() +@INPUT : tokens +@OUTPUT : first_lc + last_lc +@RETURNS : +@DESCRIPTION: Finds the first contiguous string of lowercase tokens in + `name'. The string must already be tokenized by + find_tokens(), and the input args num_tok, tok_start, and + tok_stop are the return value and the two same-named output + arguments from find_tokens(). +@GLOBALS : +@CALLS : +@CALLERS : bt_split_name() +@CREATED : 1997/05/14, Greg Ward +@MODIFIED : +-------------------------------------------------------------------------- */ +static void +find_lc_tokens (bt_stringlist * tokens, + int * first_lc, + int * last_lc) +{ + int i; /* iterate over token list this time */ + int in_lc_sequence; /* in contig. sequence of lc tokens? */ + + *first_lc = *last_lc = -1; /* haven't found either yet */ + in_lc_sequence = 0; + + i = 0; + while (i < tokens->num_items) + { + if (*first_lc == -1 && islower (tokens->items[i][0])) + { + *first_lc = i; + + i++; + while (i < tokens->num_items && islower (tokens->items[i][0])) + i++; + + *last_lc = i-1; + } + else + { + i++; + } + } +} /* find_lc_tokens() */ + + +/* ------------------------------------------------------------------------ +@NAME : resolve_token_range() +@INPUT : tokens - structure containing the token list + tok_range - two-element array with start and stop token number +@OUTPUT : *part - set to point to first token in range, or NULL + if empty range + *num_tok - number of tokens in the range +@RETURNS : +@DESCRIPTION: Given a list of tokens and a range of token numbers (as a + two-element array, tok_range), computes the number of tokens + in the range. If this is >= 0, sets *part to point + to the first token in the range; otherwise, sets *part + to NULL. +@CALLERS : +@CREATED : May 1997, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +static void +resolve_token_range (bt_stringlist *tokens, + int * tok_range, + char *** part, + int * num_tok) +{ + *num_tok = (tok_range[1] - tok_range[0]) + 1; + if (*num_tok <= 0) + { + *num_tok = 0; + *part = NULL; + } + else + { + *part = tokens->items + tok_range[0]; + } +} /* resolve_token_range() */ + + +/* ------------------------------------------------------------------------ +@NAME : split_simple_name() +@INPUT : name + first_lc + last_lc +@OUTPUT : name +@RETURNS : +@DESCRIPTION: Splits up a name (represented as a string divided into + non-overlapping, whitespace-separated tokens) according + to the BibTeX rules for names without commas. Specifically: + * tokens up to (but not including) the first lowercase + token, or the last token of the string if there + are no lowercase tokens, become the `first' part + * the earliest contiguous sequence of lowercase tokens, + up to (but not including) the last token of the string, + becomes the `von' part + * the tokens following the `von' part, or the last + single token if there is no `von' part, become + the `last' part + * there is no `jr' part +@GLOBALS : +@CALLS : name_warning() (if last lc token taken as lastname) + resolve_token_range() +@CALLERS : bt_split_name() +@CREATED : 1997/05/15, Greg Ward +@MODIFIED : +-------------------------------------------------------------------------- */ +static void +split_simple_name (name_loc * loc, + bt_name * name, + int first_lc, + int last_lc) +{ + int first_t[2], von_t[2], last_t[2]; + int end; + + end = name->tokens->num_items-1; /* token number of last token */ + + if (first_lc > -1) /* any lowercase tokens at all? */ + { + first_t[0] = 0; /* first name goes from beginning */ + first_t[1] = first_lc-1; /* to just before first lc token */ + + if (last_lc == end) /* sequence of lowercase tokens */ + { /* goes all the way to end of string */ + last_lc--; /* -- roll it back by one so we */ + /* still have a lastname */ +#ifdef WARN_LC_LASTNAME + /* + * disable this warning for now because "others" is used fairly + * often as a name in BibTeX databases -- oops! + */ + name_warning (loc, + "no capitalized token at end of name; " + "using \"%s\" as lastname", + name->tokens->items[end]); +#else +# ifndef ALLOW_WARNINGS + loc = NULL; /* avoid "unused parameter" warning */ +# endif +#endif + } + + von_t[0] = first_lc; /* `von' part covers sequence of */ + von_t[1] = last_lc; /* lowercase tokens */ + last_t[0] = last_lc+1; /* lastname from after `von' to end */ + last_t[1] = end; /* of string */ + } + else /* no lowercase tokens */ + { + von_t[0] = 0; /* empty `von' part */ + von_t[1] = -1; + first_t[0] = 0; /* `first' goes from first to second */ + first_t[1] = end-1; /* last token */ + last_t[0] = last_t[1] = end; /* and `last' is just the last token */ + } + + resolve_token_range (name->tokens, first_t, + name->parts+BTN_FIRST, name->part_len+BTN_FIRST); + resolve_token_range (name->tokens, von_t, + name->parts+BTN_VON, name->part_len+BTN_VON); + resolve_token_range (name->tokens, last_t, + name->parts+BTN_LAST, name->part_len+BTN_LAST); + name->parts[BTN_JR] = NULL; /* no jr part possible */ + name->part_len[BTN_JR] = 0; + +} /* split_simple_name() */ + + +/* ------------------------------------------------------------------------ +@NAME : split_general_name() +@INPUT : name + num_commas + comma_token + first_lc + last_lc +@OUTPUT : name +@RETURNS : +@DESCRIPTION: Splits a name according to the BibTeX rules for names + with 1 or 2 commas (> 2 commas is handled elsewhere, + namely by bt_split_name() calling find_commas() with + max_commas == 2). Specifically: + * an initial string of lowercase tokens, up to (but not + including) the token before the first comma, becomes + the `von' part + * tokens from immediately after the `von' part, + or from the beginning of the string if no `von', + up to the first comma become the `last' part + + if one comma: + * all tokens following the sole comma become the + `first' part + + if two commas: + * tokens between the two commas become the `jr' part + * all tokens following the second comma become the + `first' part +@GLOBALS : +@CALLS : name_warning() (if last lc token taken as lastname) + resolve_token_range() +@CALLERS : bt_split_name() +@CREATED : 1997/05/15, Greg Ward +@MODIFIED : +-------------------------------------------------------------------------- */ +static void +split_general_name (name_loc * loc, + bt_name * name, + int num_commas, + int * comma_token, + int first_lc, + int last_lc) +{ + int first_t[2], von_t[2], last_t[2], jr_t[2]; + int end; + + end = name->tokens->num_items-1; /* last token number */ + + if (first_lc == 0) /* we have an initial string of */ + { /* lowercase tokens */ + if (last_lc == comma_token[0]) /* lc string ends at first comma */ + { + name_warning (loc, "no capitalized tokens before first comma"); + last_lc--; + } + + von_t[0] = first_lc; /* `von' covers the sequence of */ + von_t[1] = last_lc; /* lowercase tokens */ + } + else /* no lowercase tokens at start */ + { + von_t[0] = 0; /* empty `von' part */ + von_t[1] = -1; + } + + last_t[0] = von_t[1] + 1; /* start right after end of `von' */ + last_t[1] = comma_token[0]; /* and end at first comma */ + + if (num_commas == 1) + { + first_t[0] = comma_token[0]+1; /* start right after comma */ + first_t[1] = end; /* stop at end of string */ + jr_t[0] = 0; /* empty `jr' part */ + jr_t[1] = -1; + } + else /* more than 1 comma */ + { + jr_t[0] = comma_token[0]+1; /* start after first comma */ + jr_t[1] = comma_token[1]; /* stop at second comma */ + first_t[0] = comma_token[1]+1; /* start after second comma */ + first_t[1] = end; /* and go to end */ + } + + resolve_token_range (name->tokens, first_t, + name->parts+BTN_FIRST, name->part_len+BTN_FIRST); + resolve_token_range (name->tokens, von_t, + name->parts+BTN_VON, name->part_len+BTN_VON); + resolve_token_range (name->tokens, last_t, + name->parts+BTN_LAST, name->part_len+BTN_LAST); + resolve_token_range (name->tokens, jr_t, + name->parts+BTN_JR, name->part_len+BTN_JR); + +} /* split_general_name() */ + + +/* ------------------------------------------------------------------------ +@NAME : bt_split_name() +@INPUT : name + filename + line + name_num +@OUTPUT : +@RETURNS : newly-allocated bt_name structure containing the four + parts as token-lists +@DESCRIPTION: Splits a name according to the BibTeX rules. There are + actually two sets of rules: one for names with no commas, + and one for names with 1 or 2 commas. (If a name has + more than 2 commas, the extras are removed and it's treated + as though it had just the first 2.) + + See split_simple_name() for the no-comma rules, and + split_general_name() for the 1-or-2-commas rules. + + The bt_name structure returned can (and should) be freed + with bt_free_name() when you no longer need it. +@GLOBALS : +@CALLS : +@CALLERS : anyone (exported by library) +@CREATED : 1997/05/14, Greg Ward +@MODIFIED : +@COMMENTS : The name-splitting code all implicitly assumes that the + string being split has been post-processed to collapse + whitespace in the BibTeX way. This means that it tends to + dump core on such things as leading whitespace, or more than + one space in a row inside the string. This could probably be + alleviated with a call to bt_postprocess_string(), possibly + preceded by a check for any of those occurences. Before + doing that, though, I want to examine the code carefully to + determine just what assumptions it makes -- so I can + check/correct for all of them. +-------------------------------------------------------------------------- */ +bt_name * +bt_split_name (char * name, + char * filename, + int line, + int name_num) +{ + name_loc loc; + bt_stringlist * + tokens; + int comma_token[MAX_COMMAS]; + int len; + int num_commas; + int first_lc, last_lc; + bt_name * split_name; + int i; + + DBG_ACTION (1, printf ("bt_split_name(): name=%p (%s)\n", name, name)) + + split_name = (bt_name *) malloc (sizeof (bt_name)); + if (name == NULL) + { + len = 0; + } + else + { + name = strdup (name); /* private copy that we may clobber */ + len = strlen (name); + } + + DBG_ACTION (1, printf ("bt_split_name(): split_name=%p\n", split_name)) + + if (len == 0) /* non-existent or empty string? */ + { + split_name->tokens = NULL; + for (i = 0; i < BT_MAX_NAMEPARTS; i++) + { + split_name->parts[i] = NULL; + split_name->part_len[i] = 0; + } + return split_name; + } + + loc.filename = filename; /* so called functions can generate */ + loc.line = line; /* decent warning messages */ + loc.name_num = name_num; + + num_commas = find_commas (&loc, name, MAX_COMMAS); + assert (num_commas <= MAX_COMMAS); + + DBG_ACTION (1, printf ("found %d commas: ", num_commas)) + + tokens = find_tokens (name, comma_token); + +#if DEBUG + printf ("found %d tokens:\n", tokens->num_items); + for (i = 0; i < tokens->num_items; i++) + { + printf (" %d: ", i); + + if (tokens->items[i]) /* non-empty token? */ + { + printf (">%s<\n", tokens->items[i]); + } + else + { + printf ("(empty)\n"); + } + } +#endif + +#if DEBUG + printf ("comma tokens: "); + for (i = 0; i < num_commas; i++) + printf ("%d ", comma_token[i]); + printf ("\n"); +#endif + + find_lc_tokens (tokens, &first_lc, &last_lc); +#if DEBUG + printf ("(first,last) lc tokens = (%d,%d)\n", first_lc, last_lc); +#endif + + if (strlen (name) == 0) /* name now empty? */ + { + split_name->tokens = NULL; + for (i = 0; i < BT_MAX_NAMEPARTS; i++) + { + split_name->parts[i] = NULL; + split_name->part_len[i] = 0; + } + } + else + { + split_name->tokens = tokens; + if (num_commas == 0) /* no commas -- "simple" format */ + { + split_simple_name (&loc, split_name, + first_lc, last_lc); + } + else + { + split_general_name (&loc, split_name, + num_commas, comma_token, + first_lc, last_lc); + } + } + +#if DEBUG + printf ("bt_split_name(): returning structure %p\n", split_name); +#endif + return split_name; +} /* bt_split_name() */ + + +/* ------------------------------------------------------------------------ +@NAME : bt_free_name() +@INPUT : name +@OUTPUT : +@RETURNS : +@DESCRIPTION: Frees up any memory allocated for a bt_name structure + (namely, the `tokens' field [a bt_stringlist structure, + this freed with bt_free_list()] and the structure itself.) +@CALLS : bt_free_list() +@CALLERS : anyone (exported) +@CREATED : 1997/11/14, GPW +@MODIFIED : +-------------------------------------------------------------------------- */ +void +bt_free_name (bt_name * name) +{ + DBG_ACTION (2, printf ("bt_free_name(): freeing name %p " + "(%d tokens, string=%p (%s), last[0]=%s)\n", + name, + name->tokens->num_items, + name->tokens->string, + name->tokens->string, + name->parts[BTN_LAST][0])); + bt_free_list (name->tokens); + free (name); + DBG_ACTION (2, printf ("bt_free_name(): done, everything freed\n")); +} |