/***** * StringUtil.c: badly named file with misc. routines that don't fit anywhere * else. * * This file Version $Revision: 1.5 $ * * Creation date: Wed May 29 22:35:32 GMT+0100 1996 * Last modification: $Date: 1999/07/29 01:26:28 $ * By: $Author: sopwith $ * Current State: $State: Exp $ * * Author: newt * (C)Copyright 1995 Ripley Software Development * All Rights Reserved * * Hashing routines Copyright (c) 1997 Alfredo K. Kojima * * This file is part of the XmHTML Widget Library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Source History: * ForUtil-0.52 * newt *****/ /***** * ChangeLog * $Log: StringUtil.c,v $ * Revision 1.5 1999/07/29 01:26:28 sopwith * * * Fix all warnings. * * Revision 1.4 1998/02/12 03:07:55 unammx * Merge to Koen's XmHTML 1.1.2 + following fixes: * * Wed Feb 11 20:27:19 1998 Miguel de Icaza * * * gtk-forms.c (freeForm): gtk_destroy_widget is no longer needed * with the refcounting changes. * * * gtk-xmhtml.c (gtk_xmhtml_remove): Only god knows why I was * adding the just removed widget. * * Revision 1.3 1998/01/07 01:45:34 unammx * Gtk/XmHTML is ready to be used by the Gnome hackers now! * Weeeeeee! * * This afternoon: * * - Changes to integrate gtk-xmhtml into an autoconf setup. * * - Changes to make gtk-xmhtml a library to be used by Gnome * (simply include #endif #include #include #include #include /* toupper, tolower, isspace */ #include #ifdef WITH_MOTIF # include #else # include #endif #include "XmHTMLP.h" #include "XmHTMLfuncs.h" #include "escapes.h" /*** External Function Prototype Declarations ***/ /*** Public Variable Declarations ***/ /*** * Character translation table for converting from upper to lower case * Since this is a table lookup, it might perform better than the libc * tolower routine on a number of systems. ***/ const Byte __my_translation_table[256]={ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23, 24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44, 45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,97,98, 99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115, 116,117,118,119,120,121,122,91,92,93,94,95,96,97,98,99,100,101,102, 103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119, 120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136, 137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153, 154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170, 171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187, 188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204, 205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221, 222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, 239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255}; /*** Private Function Prototype Declarations ****/ static String to_ascii(int val); static String to_roman(int val); /* convert a character escape sequence */ static char tokenToEscape(char **escape, Boolean warn); /*** Private Variable Declarations ***/ static char *Ones[] = {"i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"}; static char *Tens[] = {"x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"}; static char *Hundreds[] = {"c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"}; /***** * Name: my_upcase * Return Type: void * Description: makes a string all uppercase * In: * string: string to translate to uppercase * Returns: * nothing, string is changed upon return. *****/ void my_upcase(char *string) { register char *outPtr = string; for(outPtr = string; *outPtr != '\0'; *(outPtr++) = toupper(*(string++))); } /***** * Name: my_locase * Return Type: void * Description: make a string all lower case * In: * string: string to translate to lowercase * Returns: * nothing, string is changed upon return. *****/ void my_locase(char *string) { register char *outPtr = string; for(outPtr = string; *outPtr != '\0'; *(outPtr++) = _FastLower(*(string++))); } /***** * Name: my_strcasestr * Return Type: char * * Description: returns the starting address of s2 in s1, ignoring case * In: * s1: string to examine * s2: string to find * Returns: * a ptr to the position in s1 where s2 is found, or NULL if s2 is not found. *****/ char * my_strcasestr(const char *s1, const char *s2) { register int i; register const char *p1, *p2, *s = s1; for (p2 = s2, i = 0; *s; p2 = s2, i++, s++) { for (p1 = s; *p1 && *p2 && _FastLower(*p1) == _FastLower(*p2); p1++, p2++) ; if(!*p2) break; } if (!*p2) return((char*)s1 + i); return 0; } #ifdef DEBUG /***** * Name: __rsd_strdup * Return Type: char* * Description: debugging version of strdup * In: * s1: string to be duplicated * Returns: * duplicated string. *****/ char* __rsd_strdup(const char *s1, char *file, int line) { static char *ret_val; /* dump if failed */ my_assert(s1 != NULL); ret_val = malloc(strlen(s1)+1); strcpy(ret_val, s1); return(ret_val); } #endif /***** * Name: my_strndup * Return Type: char* * Description: duplicates up to len chars of string s1 * In: * s1: source string; * len: max no of chars to copy; * Returns: * a ptr to the duplicated string, padded with NULL if len is larger then * s1. Return value is always NULL terminated. *****/ char * my_strndup(const char *s1, size_t len) { register int i; register char *p2; register const char *p1 = s1; static char *s2; /* no negative lengths */ if(len < 0 || s1 == NULL || *s1 == '\0') return(NULL); /* size of text + a terminating \0 */ s2 = (char*)malloc(len+1); for(p2 = s2, i = 0; *p1 && i < len; *(p2++) = *(p1++), i++); /* NULL padding */ while(i++ < len) *(p2++) = '\0'; *p2 = '\0'; /* NULL terminate */ return(s2); } /***** * UnixWare doesn't have these functions in its standard C library * contributed by Thanh Ma (tma@encore.com), fix 02/03/97-03, tma *****/ #ifdef NEED_STRCASECMP /***** * Name: strncasecmp * Return Type: int * Description: case insensitive string compare upto n characters of string * s1. * In: * s1: source string * s2: string to compare with * n: no of characters to compare. * Returns: * 0 when they match, character difference otherwise. *****/ int my_strncasecmp (const char *s1, const char *s2, size_t n) { register int c1, c2, l=0; while (*s1 && *s2 && l < n) { c1 = _FastLower(*s1); c2 = _FastLower(*s2); if (c1 != c2) return(c1 - c2); s1++; s2++; l++; } return((int)(0)); } /***** * Name: strcasecmp * Return Type: int * Description: case insensitive string compare * In: * s1: source string * s2: string to compare with * Returns: * 0 when they match, character difference otherwise. *****/ int my_strcasecmp (const char *s1, const char *s2) { register int c1, c2; while (*s1 && *s2) { c1 = _FastLower(*s1); c2 = _FastLower(*s2); if (c1 != c2) return(c1 - c2); s1++; s2++; } return((int)(*s1 - *s2)); } #endif /* NEED_STRCASECMP */ /***** * string to number routines *****/ /***** * Name: to_ascii * Return Type: String * Description: converts a numerical value to an abc representation. * In: * val: number to convert * Returns: * converted number. *****/ static String to_ascii(int val) { int remainder, i = 0, j = 0, value = val; char number[10]; static char out[10]; /* return buffer */ do { remainder = (value % 26); number[i++] = (remainder ? remainder + 96 : 'z'); } while((value = (remainder ? (int)(value/26) : (int)((value-1)/26))) && i < 10); /* no buffer overruns */ for(j = 0; i > 0 && j < 10; i--, j++) out[j] = number[i-1]; out[j] = '\0'; /* NULL terminate */ return(out); } /***** * Name: to_roman * Return Type: String * Description: converts the given number to a lowercase roman numeral. * In: * val: number to convert * Returns: * converted number * Note: * This routine is based on a similar one found in the Arena browser. *****/ static String to_roman(int val) { int value, one, ten, hundred, thousand; static char buf[20], *p, *q; value = val; /* * XmHTML probably crashes **long** before a number with value 10^20 is * reached. */ sprintf(buf, "%i", val); thousand = value/1000; value = value % 1000; hundred = value/100; value = value % 100; ten = value/10; one = value % 10; p = buf; while(thousand-- > 0) *p++ = 'm'; if(hundred) { q = Hundreds[hundred-1]; while ((*p++ = *q++)); --p; } if(ten) { q = Tens[ten-1]; while ((*p++ = *q++)); --p; } if(one) { q = Ones[one-1]; while ((*p++ = *q++)); --p; } *p = '\0'; return(buf); } /***** * Name: ToAsciiLower * Return Type: String * Description: returns the abc representation of the given number * In: * val: number to convert * Returns: * converted number *****/ String ToAsciiLower(int val) { return((to_ascii(val))); } /***** * Name: ToAsciiUpper * Return Type: String * Description: returns the ABC representation of the given number * In: * val: number to convert * Returns: * converted number *****/ String ToAsciiUpper(int val) { static String buf; buf = to_ascii(val); my_upcase(buf); return(buf); } /***** * Name: ToRomanLower * Return Type: String * Description: converts numbers between 1-3999 to roman numerals, lowercase. * In: * value: value to convert * Returns: * lowercase roman numeral *****/ String ToRomanLower(int val) { return(to_roman(val)); } /***** * Name: ToRomanUpper * Return Type: String * Description: converts numbers between 1-3999 to roman numerals, uppercase. * In: * value: value to convert * Returns: * uppercase roman numeral *****/ String ToRomanUpper(int val) { static String buf; buf = to_roman(val); my_upcase(buf); return(buf); } /***** * HTML Tag analyzers *****/ /***** * Name: tokenToEscape * Return Type: char * Description: converts the HTML & escapes sequences to the appropriate char. * In: * **escape: escape sequence to convert. This argument is updated upon * return. * warn: warning issue flag; * Returns: * the character representation of the given escape sequence * * Note: this routine uses a sorted table defined in the header file escapes.h * and uses a binary search to locate the appropriate character for the given * escape sequence. * This table contains the hashed escapes as well as the named escapes. * The number of elements is NUM_ESCAPES (currently 197), so a match is always * found in less than 8 iterations (2^8=256). * If an escape sequence is not matched and it is a hash escape, the value * is assumed to be below 160 and converted to a char using the ASCII * representation of the given number. For other, non-matched characters, 0 * is returned and the return pointer is updated to point right after the * ampersand sign. *****/ static char tokenToEscape(char **escape, Boolean warn) { register int mid, lo = 0, hi = NUM_ESCAPES -1; int cmp, skip = 1; char tmp[8]; /* * first check if this is indeed an escape sequence. * It's much more cost-effective to do this test here instead of in * the calling routine. */ if(*(*escape+1) != '#' && !(isalpha(*(*escape+1)))) { if(warn) { /* bad escape, spit out a warning and continue */ strncpy(tmp, *escape, 7); tmp[7] = '\0'; _XmHTMLWarning(__WFUNC__(NULL, "tokenToEscape"), "Invalid escape sequence: %s...", tmp); } /* skip and return */ *escape += 1; return('&'); } /* * run this loop twice: one time with a ; assumed present and one * time with ; present. */ for(skip = 0; skip != 2; skip++) { lo = 0; hi = NUM_ESCAPES - 1; while(lo <= hi) { mid = (lo + hi)/2; if((cmp = strncmp(*escape+1, escapes[mid].escape, escapes[mid].len - skip)) == 0) { /* update ptr to point right after the escape sequence */ *escape += escapes[mid].len + (1 - skip); return(escapes[mid].token); } else if(cmp < 0) /* in lower end of array */ hi = mid - 1; else /* in higher end of array */ lo = mid + 1; } } /* * If we get here, the escape sequence wasn't matched: big chance * it uses a &# escape below 160. To deal with this, we pick up the numeric * code and convert to a plain ASCII value which is returned to the * caller */ if( *(*escape+1) == '#') { char *chPtr, ret_char; int len = 0; *escape += 2; /* skip past the &# sequence */ chPtr = *escape; while(isdigit(*chPtr)) { chPtr++; len++; } if(*chPtr == ';') { *chPtr = '\0'; /* null out the ; */ len++; } ret_char = (char)atoi(*escape); /* get corresponding char */ /* move past the escape sequence */ if(*(*escape + len) == ';') *escape += len + 1; else *escape += len; return(ret_char); } /* bad escape, spit out a warning and continue */ if(warn) { strncpy(tmp, *escape, 7); tmp[7] = '\0'; _XmHTMLWarning(__WFUNC__(NULL, "tokenToEscape"), "Invalid escape sequence %s...", tmp); } *escape += 1; return('&'); } /***** * Name: _XmHTMLExpandEscapes * Return Type: void * Description: replaces character escapes sequences with the appropriate char. * In: * string: text to scan for escape sequences * Returns: * nothing *****/ void _XmHTMLExpandEscapes(char *string, Boolean warn) { register char *chPtr = string; char escape; /* value of escape character */ /* scan the entire text in search of escape codes (yuck) */ while(*string) /* fix 02/26/97-02, dp */ { switch(*string) { case '&': if((escape = tokenToEscape(&string, warn)) != 0) *chPtr++ = escape; break; default: *(chPtr++) = *(string++); } if(*string == 0) { *chPtr = '\0'; /* NULL terminate */ return; } } } /***** * Name: _XmHTMLTagCheck * Return Type: Boolean * Description: checks whether the given tag exists in the attributes of a * HTML element * In: * attributes: attributes from an HTML element * tag: tag to look for. * Returns: * True if tag is found, False otherwise. *****/ Boolean _XmHTMLTagCheck(char *attributes, char *tag) { char *chPtr, *start; /* sanity check */ if(attributes == NULL) return(False); if((chPtr = my_strcasestr(attributes, tag)) != NULL) { /* see if this is a valid tag: it must be preceeded with whitespace. */ while(*(chPtr-1) && !isspace(*(chPtr-1))) { start = chPtr+strlen(tag); /* start right after this element */ if((chPtr = my_strcasestr(start, tag)) == NULL) return(False); } if(chPtr) return(True); else return(False); } return(False); } /***** * Name: _XmHTMLTagGetValue * Return Type: char * * Description: looks for the specified tag in the given list of attributes. * In: * attributes: attributes from an HTML element * tag: tag to look for. * Returns: * if tag exists, the value of this tag, NULL otherwise. * return value is always malloc'd; caller must free it. *****/ String _XmHTMLTagGetValue(char *attributes, char *tag) { static char *buf; char *chPtr, *start, *end; if(attributes == NULL || tag == NULL) /* sanity check */ return(NULL); _XmHTMLDebug(4, ("parse.c: _XmHTMLTagGetValue, attributes: %s, tag %s\n", attributes, tag)); if((chPtr = my_strcasestr(attributes, tag)) != NULL) { /* * check if the ptr obtained is correct, eg, no whitespace before it. * If this is not the case, get the next match. * Need to do this since a single my_strcasestr on, for example, align * will match both align _and_ valign. */ while(*(chPtr-1) && !isspace(*(chPtr-1))) { start = chPtr+strlen(tag); /* start right after this element */ if((chPtr = my_strcasestr(start, tag)) == NULL) return(NULL); } if(chPtr == NULL) return(NULL); start = chPtr+strlen(tag); /* start right after this element */ /* remove leading spaces */ while(isspace(*start)) start++; /* if no '=', return NULL */ if(*start != '=') { _XmHTMLDebug(4, ("parse.c: _XmHTMLTagGetValue, tag has no " "= sign.\n")); return(NULL); } start++; /* move past the '=' char */ /* remove more spaces */ while(*start != '\0' && isspace(*start)) start++; /* sanity check */ if(*start == '\0') { #ifdef PEDANTIC _XmHTMLWarning(__WFUNC__(NULL, "_XmHTMLTagGetValue"), "tag %s has no value.", tag); #endif /* PEDANTIC */ return(NULL); } /* unquoted tag values are treated differently */ if(*start != '\"') { for(end = start; !(isspace(*end)) && *end != '\0' ; end++); } else { start++; for(end = start; *end != '\"' && *end != '\0' ; end++); } /* empty string */ if(end == start) return(NULL); buf = my_strndup(start, end - start); _XmHTMLDebug(4, ("parse.c: _XmHTMLTagGetValue, returning %s\n", buf)); return(buf); } return(NULL); } /***** * Name: _XmHTMLTagGetNumber * Return Type: int * Description: retrieves the numerical value of the given tag. * In: * attributes: attributes from an HTML element * tag: tag to look for. * def: default value if tag is not found. * Returns: * if tag exists, the value of this tag, def otherwise *****/ int _XmHTMLTagGetNumber(char *attributes, char *tag, int def) { char *chPtr; int ret_val = def; if((chPtr = _XmHTMLTagGetValue(attributes, tag)) != NULL) { ret_val = atoi(chPtr); _XmHTMLDebug(4, ("parse.c: _XmHTMLTagGetNumber, value for tag %s " "is %i\n", tag, ret_val)); free(chPtr); } return(ret_val); } /***** * Name: _XmHTMLTagCheckNumber * Return Type: int * Description: retrieves the numerical value of the given tag. * If the returned no is negative, the specified value was * a relative number. Otherwise it's an absolute number. * In: * attributes: attributes from an HTML element * tag: tag to look for. * def: default value if tag is not found. * Returns: * if tag exists, the value of this tag, def otherwise *****/ int _XmHTMLTagCheckNumber(char *attributes, char *tag, int def) { int ret_val = def; char *chPtr; /* get the requested tag */ if((chPtr = _XmHTMLTagGetValue(attributes, tag)) != NULL) { /* when len is negative, a percentage has been used */ if((strpbrk(chPtr, "%")) != NULL || (strpbrk (chPtr, "*")) != NULL) ret_val = -1*atoi(chPtr); else ret_val = atoi(chPtr); free(chPtr); } return(ret_val); } /***** * Name: _XmHTMLTagCheckValue * Return Type: Boolean * Description: checks whether the specified tag in the given list of attributes * has a certain value. * In: * attributes: attributes from an HTML element * tag: tag to look for. * check: value to check. * Returns: * returns True if tag exists and has the correct value, False otherwise. *****/ Boolean _XmHTMLTagCheckValue(char *attributes, char *tag, char *check) { char *buf; _XmHTMLDebug(4, ("parse.c: _XmHTMLTagCheckValue: tag %s, check %s\n", tag, check)); /* no sanity check, TagGetValue returns NULL if attributes is empty */ if((buf = _XmHTMLTagGetValue(attributes, tag)) == NULL || strcasecmp(buf, check)) { if(buf != NULL) free(buf); return(False); } free(buf); /* fix 12-21-96-01, kdh */ return(True); } /***** * Name: _XmHTMLGetImageAlignment * Return Type: Alignment * Description: returns any specified image alignment * In: * attributes: attributes * Returns: * specified image alignment. If none found, XmVALIGN_BOTTOM *****/ Alignment _XmHTMLGetImageAlignment(char *attributes) { char *buf; Alignment ret_val = XmVALIGN_BOTTOM; /* First check if this tag does exist */ if((buf = _XmHTMLTagGetValue(attributes, "align")) == NULL) return(ret_val); /* transform to lowercase */ my_locase(buf); if(!(strcmp(buf, "left"))) ret_val = XmHALIGN_LEFT; else if(!(strcmp(buf, "right"))) ret_val = XmHALIGN_RIGHT; else if(!(strcmp(buf, "top"))) ret_val = XmVALIGN_TOP; else if(!(strcmp(buf, "middle"))) ret_val = XmVALIGN_MIDDLE; else if(!(strcmp(buf, "bottom"))) ret_val = XmVALIGN_BOTTOM; else if(!(strcmp(buf, "baseline"))) ret_val = XmVALIGN_BASELINE; free(buf); /* fix 01/12/97-01; kdh */ return(ret_val); } /***** * Name: _XmHTMLGetHorizontalAlignment * Return Type: Alignment * Description: Retrieve the value of the ALIGN attribute * In: * attributes: attributes to check for the ALIGN tag * def_align: default alignment. * Returns: * selected ALIGN enumeration type or def_align if no match is found. *****/ Alignment _XmHTMLGetHorizontalAlignment(char *attributes, Alignment def_align) { char *buf; Alignment ret_val = def_align; /* First check if this tag does exist */ if((buf = _XmHTMLTagGetValue(attributes, "align")) == NULL) return(ret_val); /* transform to lowercase */ my_locase(buf); if(!(strcmp(buf, "center"))) ret_val = XmHALIGN_CENTER; else if(!(strcmp(buf, "right"))) ret_val = XmHALIGN_RIGHT; else if(!(strcmp(buf, "justify"))) ret_val = XmHALIGN_JUSTIFY; else if(!(strcmp(buf, "left"))) ret_val = XmHALIGN_LEFT; free(buf); /* fix 01/12/97-01; kdh */ return(ret_val); } /***** * Name: _XmHTMLGetVerticalAlignment * Return Type: Alignment * Description: Retrieve the value of the VALIGN attribute * In: * attributes: attributes to check for the VALIGN tag * Returns: * selected VALIGN enumeration type or XmVALIGN_TOP when no valign tag * is found among the element's attributes. *****/ Alignment _XmHTMLGetVerticalAlignment(char *attributes, Alignment def_align) { char *buf; Alignment ret_val = def_align; /* First check if this tag does exist */ if((buf = _XmHTMLTagGetValue(attributes, "valign")) == NULL) return(ret_val); if(!(strcmp(buf, "top"))) ret_val = XmVALIGN_TOP; else if(!(strcmp(buf, "middle"))) ret_val = XmVALIGN_MIDDLE; else if(!(strcmp(buf, "bottom"))) ret_val = XmVALIGN_BOTTOM; else if(!(strcmp(buf, "baseline"))) ret_val = XmVALIGN_BASELINE; free(buf); /* fix 01/12/97-02; kdh */ return(ret_val); } TableFraming _XmHTMLGetFraming(String attributes, TableFraming def) { char *buf; TableFraming ret_val = def; /* First check if this tag does exist */ if((buf = _XmHTMLTagGetValue(attributes, "frame")) == NULL) return(ret_val); if(!(strcmp(buf, "void"))) ret_val = TFRAME_VOID; else if(!(strcmp(buf, "above"))) ret_val = TFRAME_ABOVE; else if(!(strcmp(buf, "below"))) ret_val = TFRAME_BELOW; else if(!(strcmp(buf, "hsides"))) ret_val = TFRAME_HSIDES; else if(!(strcmp(buf, "lhs"))) ret_val = TFRAME_LEFT; else if(!(strcmp(buf, "rhs"))) ret_val = TFRAME_RIGHT; else if(!(strcmp(buf, "vsides"))) ret_val = TFRAME_VSIDES; else if(!(strcmp(buf, "box"))) ret_val = TFRAME_BOX; else if(!(strcmp(buf, "border"))) ret_val = TFRAME_BORDER; free(buf); return(ret_val); } TableRuling _XmHTMLGetRuling(String attributes, TableRuling def) { char *buf; TableRuling ret_val = def; /* First check if this tag does exist */ if((buf = _XmHTMLTagGetValue(attributes, "rules")) == NULL) return(ret_val); if(!(strcmp(buf, "none"))) ret_val = TRULE_NONE; else if(!(strcmp(buf, "groups"))) ret_val = TRULE_GROUPS; else if(!(strcmp(buf, "rows"))) ret_val = TRULE_ROWS; else if(!(strcmp(buf, "cols"))) ret_val = TRULE_COLS; else if(!(strcmp(buf, "all"))) ret_val = TRULE_ALL; free(buf); return(ret_val); } /***** * Name: _XmHTMLGetMaxLineLength * Return Type: Dimension * Description: returns an estimated guess on how wide the formatted document * will be based on the longest line in the document source. * In: * html: XmHTMLWidget id * Returns: * guess what? *****/ Dimension _XmHTMLGetMaxLineLength(XmHTMLWidget html) { Dimension max = 0, ret_val = 0; int i; String chPtr; XmHTMLObject *tmp; for(tmp = html->html.elements; tmp != NULL; tmp = tmp->next) { if(tmp->id == HT_ZTEXT) { chPtr = tmp->element; i = 0; /***** * Count all chars. Tabs are expanded and newlines reset the * linewidth. *****/ for(chPtr = tmp->element; *chPtr != '\0'; chPtr++) { switch(*chPtr) { case '\t': i = ((i/8)+1)*8; break; case '\n': if(ret_val < i) ret_val = i; i = -1; default: i++; } } /* long lines without a newline */ if(ret_val < i) ret_val = i; } } /* assume 80 chars if no text found */ if(ret_val == 0) ret_val = 80; /* assume an average width of 7 pixels per character */ ret_val *= 7; /* we allow widths up to 75% of the screen width */ max = (Dimension)(0.75*Toolkit_Screen_Width (html)); ret_val = (ret_val > max ? max : ret_val); _XmHTMLDebug(4, ("parse.c: _XmHTMLGetMaxLineLength, returning %d\n", ret_val)); return(ret_val); } /***** * Debugging memory functions. * These *must* be kept at the end of this file as it overrides any * previously defined memory allocation macros. *****/ #ifdef DEBUG /* need to undefine them or w'll get in an endless loop */ #undef malloc #undef calloc #undef realloc #undef free char* __rsd_malloc(size_t size, char *file, int line) { static char *ret_val; my_assert(size != 0); ret_val = (char*) malloc (size); /* dump if failed */ my_assert(ret_val != NULL); return(ret_val); } char* __rsd_calloc(size_t nmemb, size_t size, char *file, int line) { static char *ret_val; my_assert(nmemb != 0); ret_val = (char*) calloc (nmemb, size); /* dump if failed */ my_assert(ret_val != NULL); return(ret_val); } char* __rsd_realloc(void *ptr, size_t size, char *file, int line) { static char *ret_val; if(size == 0) { my_assert(ptr != NULL); free (ptr); return(NULL); } ret_val = (char*) realloc (ptr, size); /* dump if failed */ my_assert(ret_val != NULL); return(ret_val); } void __rsd_free(void *ptr, char *file, int line) { my_assert(ptr != NULL); free (ptr); } #endif /* DEBUG && !DMALLOC */