/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* $XConsortium: FormatUtil.c /main/9 1996/11/01 10:12:14 drk $ */ /************************************<+>************************************* **************************************************************************** ** ** File: FormatUtil.c ** ** Project: Text Graphic Display Library ** ** ** Description: Semi private format utility functions that do not ** require the Display Area, Motif, Xt or X11. ** ** ** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company ** ** (c) Copyright 1993, 1994 Hewlett-Packard Company ** (c) Copyright 1993, 1994 International Business Machines Corp. ** (c) Copyright 1993, 1994 Sun Microsystems, Inc. ** (c) Copyright 1993, 1994 Novell, Inc. ** ** **************************************************************************** ************************************<+>*************************************/ /* * system includes */ #include #include #include #include #include #include #include #include #include #ifdef X_NOT_STDC_ENV extern int errno; #endif /* * Canvas Engine includes */ #include "CanvasP.h" #include "CanvasSegP.h" /* * private includes */ #include "CanvasError.h" #include "bufioI.h" #include "FormatUtilI.h" #if defined(NLS16) || !defined(NO_MESSAGE_CATALOG) #include
#endif #ifndef NL_CAT_LOCALE static const int NL_CAT_LOCALE = 0; #endif /******** Private Function Declarations ********/ /******** End Private Function Declarations ********/ /****************************************************************************** * * Private variables and defines. * *****************************************************************************/ #define GROW_SIZE 5 /****************************************************************************** * * Private Functions * *****************************************************************************/ /****************************************************************************** * * Semi Public Functions * *****************************************************************************/ /****************************************************************************** * Function: int _DtHelpCeAddOctalToBuf (char *src, char **dst, * int *dst_size, * int *dst_max, int grow_size) * * Parameters: * src Specifies a pointer to a string. * dst Specifies a pointer to the buffer to * to hold the information. * dst_size Specifies the current size of 'dst'. * Returns the new size of 'dst'. * dst_max Specifies the current maximum size of 'dst'. * Returns the new maximum size of 'dst'. * grow_size Specifies the minimum grow size of 'dst' * when a malloc/realloc occurs. * If this is less than one, 'dst' will * grow only large enough to hold * the new character. * * Returns: 0 if successful, -1 if errors. * * errno Values: * EINVAL * CEErrorMalloc * * Purpose: (Re-)Allocates, if necessary, enough memory to hold the old * information plus the byte. * Coverts the 0xXX value pointed to by src to a 0-256 by value. * Appends the character to the buffer pointed to 'dst'. * Updates 'dst_size' to include the new character. * Updates 'dst_max' to the new size of 'dst' if a * malloc/realloc occurred. * *****************************************************************************/ int _DtHelpCeAddOctalToBuf( char *src, char **dst, int *dst_size, int *dst_max, int grow_size ) { char tmp; char *dstPtr; unsigned long value; if (src == NULL || dst == NULL || dst_size == NULL || dst_max == NULL || (*dst == NULL && (*dst_size || *dst_max))) { errno = EINVAL; return -1; } dstPtr = *dst; if ((*dst_size + 2) >= *dst_max) { if (grow_size > *dst_size + 3 - *dst_max) *dst_max = *dst_max + grow_size; else *dst_max = *dst_size + 3; if (dstPtr) dstPtr = (char *) realloc ((void *) dstPtr, *dst_max); else { dstPtr = (char *) malloc (sizeof(char) * (*dst_max)); *dst_size = 0; } *dst = dstPtr; } /* * check to see if we have good memory */ if (!dstPtr) { errno = CEErrorMalloc; return -1; } tmp = src[4]; src[4] = '\0'; value = strtoul (src, NULL, 16); src[4] = tmp; if ((value == ULONG_MAX && errno == ERANGE) || value > 255 || value < 1) { errno = CEErrorFormattingValue; return -1; } /* * copy the source into the destination */ dstPtr[*dst_size] = (char ) value; /* * adjust the pointers. */ *dst_size = *dst_size + 1; /* * null the end of the buffer. */ dstPtr[*dst_size] = '\0'; return 0; } /****************************************************************************** * Function: int __CEAppendCharToInfo (char **src, char **dst, int *dst_size, * int *dst_max, int grow_size) * * Parameters: * src Specifies a pointer to a string. * dst Specifies a pointer to the buffer to * to hold the information. * dst_size Specifies the current size of 'dst'. * Returns the new size of 'dst'. * dst_max Specifies the current maximum size of 'dst'. * Returns the new maximum size of 'dst'. * grow_size Specifies the minimum grow size of 'dst' * when a malloc/realloc occurs. * If this is less than one, 'dst' will * grow only large enough to hold * the new character. * * Returns: 0 if successful, -1 if errors. * * errno Values: * EINVAL * CEErrorMalloc * * Purpose: (Re-)Allocates, if necessary, enough memory to hold the old * information plus the new. * Appends the character pointed to by 'src' to the buffer * pointed to 'dst'. * Updates 'src' to point to the next character after the * one appended to 'dst'. * Updates 'dst_size' to include the new character. * Updates 'dst_max' to the new size of 'dst' if a * malloc/realloc occurred. * *****************************************************************************/ int _DtHelpCeAddCharToBuf( char **src, char **dst, int *dst_size, int *dst_max, int grow_size ) { char *srcPtr; char *dstPtr; if (src == NULL || *src == NULL || dst == NULL || dst_size == NULL || dst_max == NULL || (*dst == NULL && (*dst_size || *dst_max))) { errno = EINVAL; return -1; } srcPtr = *src; dstPtr = *dst; if ((*dst_size + 2) >= *dst_max) { if (grow_size > *dst_size + 3 - *dst_max) *dst_max = *dst_max + grow_size; else *dst_max = *dst_size + 3; if (dstPtr) dstPtr = (char *) realloc ((void *) dstPtr, *dst_max); else { dstPtr = (char *) malloc (*dst_max); *dst_size = 0; } *dst = dstPtr; } /* * check to see if we have good memory */ if (!dstPtr) { errno = CEErrorMalloc; return -1; } /* * copy the source into the destination */ dstPtr[*dst_size] = *srcPtr++; /* * adjust the pointers. */ *src = srcPtr; *dst_size = *dst_size + 1; /* * null the end of the buffer. */ dstPtr[*dst_size] = '\0'; return 0; } /****************************************************************************** * Function: int _DtHelpCeAddStrToBuf (char **src, char **dst, int *dst_size, * int *dst_max, int copy_size, int grow_size) * * Parameters: * src Specifies a pointer to a string. * dst Specifies a pointer to the buffer to * to hold the information. * dst_size Specifies the current size of 'dst'. * Returns the new size of 'dst'. * dst_max Specifies the current maximum size of 'dst'. * Returns the new maximum size of 'dst'. * copy_size Specifies the number of characters to * copy from 'src' to 'dst'. * grow_size Specifies the minimum grow size of 'dst' * when a malloc/realloc occurs. * If this is less than one, 'dst' will * grow only large enough to hold * the new character. * * Returns: 0 if successful, -1 if errors. * * errno Values: * EINVAL * CEErrorMalloc * * Purpose: Copys 'copy_size' number of characters of 'src' * to 'dst'. * Updates 'src', to point after 'copy_size' number of * characters. * Updates the 'dst_size' to reflect the number of characters * copied. * If required, increments dst_max and (re)allocs memory * to hold the extra 'copy_size' number of characters. * *****************************************************************************/ int _DtHelpCeAddStrToBuf ( char **src, char **dst, int *dst_size, int *dst_max, int copy_size, int grow_size ) { char *srcPtr; char *dstPtr; /* * check the input */ if (src == NULL || *src == NULL || (((int)strlen(*src)) < copy_size) || dst == NULL || dst_size == NULL || dst_max == NULL || (*dst == NULL && (*dst_size || *dst_max))) { errno = EINVAL; return -1; } srcPtr = *src; dstPtr = *dst; if ((*dst_size + copy_size + 1) >= *dst_max) { if (grow_size > (*dst_size + copy_size + 2 - *dst_max)) *dst_max = *dst_max + grow_size; else *dst_max = *dst_size + copy_size + 2; if (dstPtr) dstPtr = (char *) realloc ((void *) dstPtr, *dst_max); else { dstPtr = (char *) malloc (*dst_max); *dst_size = 0; } *dst = dstPtr; } if (!dstPtr) { errno = CEErrorMalloc; return -1; } /* * make sure there is a null byte to append to. */ dstPtr[*dst_size] = '\0'; /* * copy the source into the destination */ strncat (dstPtr, srcPtr, copy_size); /* * adjust the pointers */ *src = srcPtr + copy_size; *dst_size = *dst_size + copy_size; return 0; } /****************************************************************************** * Function: int _DtHelpCeGetNxtBuf (FILE *file, char *dst, char **src, * int max_size) * * Parameters: * file Specifies a stream to read from. * dst Specifies the buffer where new information * is placed. * src Specifies a pointer into 'dst'. If there * is information left over, it * is moved to the begining of 'dst'. * Returns 'src' pointing to 'dst'. * max_size Specifies the maximum size of 'dst'. * * Returns: 0 if this is the last buffer that can be read for the topic. * -1 if errors. * >0 if more to be read. * * errno Values: * read (2) Errors set via a read call. * EINVAL * CEErrorReadEmpty * * Purpose: Reads the next buffer of information. * *****************************************************************************/ int _DtHelpCeGetNxtBuf( BufFilePtr file, char *dst, char **src, int max_size) { int leftOver; int result; if (file == NULL) { errno = EINVAL; return -1; } (void ) strcpy (dst, (*src)); leftOver = strlen (dst); result = _DtHelpCeReadBuf (file, &(dst[leftOver]), (max_size - leftOver)); /* * check to see if we ran into trouble reading this buffer * of information. If not reset the pointer to the beginning * of the buffer. */ if (result != -1) *src = dst; return result; } /****************************************************************************** * Function: int _DtHelpCeReadBuf (FILE *file, char *buffer, int size) * * Parameters: FILE Specifies the stream to read from. * buffer Specifies a buffer to read information * into. * size Specifies the maximum number of bytes * 'buffer' can contain. It should never be * larger than 'buffer' can hold, but it can * be smaller. * * Returns: 0 if this is the last buffer that can be read for the topic. * -1 if errors. * >0 if more to be read. * * errno Values: * read (2) Errors set via a read call. * * Purpose: Get size-1 number of bytes into a buffer and possibly * check for page markers imbedded within the text. * *****************************************************************************/ int _DtHelpCeReadBuf( BufFilePtr file, char *buffer, int size) { int flag; /* * take into account the last byte must be an end of string marker. */ size--; flag = _DtHelpCeBufFileRd(file, buffer, size); if (flag != -1) buffer[flag] = '\0'; return flag; } /* End _DtHelpCeReadBuf */ /****************************************************************************** * Function: char *_DtHelpGetNxtToken (char *str, char **retToken) * * Parameters: * str The string (in memory) which is being * parsed. * retToken Returns the next token from the input. * Valid tokens are strings of non-whitespace * characters, newline ("\n"), and * end-of-data (indicated by a zero length * string). * * A NULL value indicates an error. * * Newline or zero length strings are * not owned by the caller. * * Otherwise, the memory for the returned * token is owned by the caller. * * Return Value: Returns the pointer to the next unparsed character in * the input string. A NULL value indicates an error. * * errno Values: * EINVAL * CEErrorMalloc * * Purpose: Parse tokens in resource string values. * *****************************************************************************/ char * _DtHelpGetNxtToken ( char *str, char **retToken) { int len = 1; char *start; char *token; short quote = False; short done = False; if (retToken) *retToken = NULL; /* tested in caller code */ if (str == NULL || *str == '\0' || retToken == NULL) { errno = EINVAL; return NULL; } /* Find the next token in the string. The parsing rules are: - Whitespace (except for \n) separates tokens. - \n is a token itself. - The \0 at the end of the string is a token. */ /* Skip all of the whitespace (except for \n). */ while (*str && (*str != '\n') && isspace (*str)) str++; /* Str is pointing at the start of the next token. Depending on the type of token, malloc the memory and copy the token value. */ if (*str == '\0') token = strdup(str); else if (*str == '\n') { token = strdup(str); str++; } else { /* We have some non-whitespace characters. Find the end of */ /* them and copy them into new memory. */ if ((MB_CUR_MAX == 1 || mblen (str, MB_CUR_MAX) == 1) && *str == '\"') { /* * found a quoted token - skip the quote. */ quote = True; str++; } start = str; while (*str && !done) { /* * get the length of the item. */ len = 1; if (MB_CUR_MAX != 1) { len = mblen (str, MB_CUR_MAX); if (len < 0) len = 1; } if (len == 1) { /* * check for the token terminator */ if ((quote && *str == '\"') || (!quote && (isspace (*str) || *str == '\n'))) done = True; else str++; } else str += len; } /* * determine the length of the token. */ token = (char *) malloc ((str - start + 1) * sizeof (char)); if (token) { strncpy (token, start, str - start); *(token + (str - start)) = '\0'; } else errno = CEErrorMalloc; /* * skip the quote terminator */ if (quote && len == 1 && *str == '\"') str++; } *retToken = token; return (str); } /****************************************************************************** * Function: _DtCvSegment *_DtHelpAllocateSegments(int malloc_size) * * Parameters: * malloc_size Specifies the number of segments to * allocate if 'alloc_size' is NULL or less * than 1 or if '*next_seg' is NULL. The * first one is returned to the caller with * the rest in 'next_seg' if 'next_seg' is * non-NULL. * * Return Value: * non-null If succeeds. * Null If failure. * * Purpose: Allocate a block of segments, zeros the structures, and * sets the link_idx of each structure to -1. * *****************************************************************************/ _DtCvSegment * _DtHelpAllocateSegments ( int malloc_size) { int i; _DtCvSegment *newSeg; FrmtPrivateInfo *p; /* * don't allow zero or negative allocations */ if (malloc_size < 1) malloc_size = 1; /* * allocate the block of segments */ newSeg = (_DtCvSegment *) calloc (sizeof(_DtCvSegment), malloc_size); if (NULL != newSeg) { /* * now allocate the same number of private information structures */ p = (FrmtPrivateInfo *) calloc (sizeof(FrmtPrivateInfo), malloc_size); if (NULL != p) { /* * mark the first item as the top block. Since it will be * attached to the first segment, it marks both the segment * and the private information blocks for later frees. */ p->top_block = True; for (i = 0; i < malloc_size; i++) { /* * invalidate the link index and attach a private * information structure to each segment */ newSeg[i].link_idx = -1; newSeg[i].client_use = p++; } } else { /* * had trouble allocating the private information. * free the new segment list and return NULL as an error. */ free(newSeg); newSeg = NULL; } } return newSeg; } /****************************************************************************** * Function: int _DtHelpFmtFindBreak (char *ptr, int mb_len, int *num_chars) * * Parameters: * ptr Specifies the string to check. * mb_len Specifies if the sequence should be single * byte or multi-byte. * num_chars Returns the character count. * * Returns number of bytes in the sequence. * * errno Values: * * Purpose: Find a length of 'ptr' comprised of multi or single byte * characters. * *****************************************************************************/ int _DtHelpFmtFindBreak ( char *ptr, int mb_len, int *num_chars) { int len = 0; int numChars = 0; int mySize; short done = 0; while (0 == done && '\0' != *ptr) { mySize = mblen(ptr, MB_CUR_MAX); done = 1; if (0 < mySize && ((1 != mb_len && 1 != mySize) || (1 == mb_len && 1 == mySize))) { numChars++; ptr += mySize; len += mySize; done = 0; } } *num_chars = numChars; return len; } /****************************************************************************** * Function: _DtHelpLoadMultiInfo * * Returns: Loads the multi-byte formatting table for the current locale. * *****************************************************************************/ void _DtHelpLoadMultiInfo ( wchar_t **cant_begin_chars, wchar_t **cant_end_chars, short *nl_to_space) { #ifndef NO_MESSAGE_CATALOG int len; char *ptr; nl_catd cat_fd; cat_fd = CATOPEN("fmt_tbl", NL_CAT_LOCALE); if (cat_fd != ((nl_catd) -1)) { /* * Get the list of characters that can't begin a line. */ ptr = CATGETS(cat_fd, 1, 1, ""); len = strlen (ptr) + 1; *cant_begin_chars = (wchar_t *) malloc (len * sizeof (wchar_t)); if (NULL != *cant_begin_chars && mbstowcs(*cant_begin_chars, ptr, len) == -1) { free (*cant_begin_chars); *cant_begin_chars = NULL; } /* * Get the list of characters that can't end a line. */ ptr = CATGETS(cat_fd, 1, 2, ""); len = strlen (ptr) + 1; *cant_end_chars = (wchar_t *) malloc (len * sizeof (wchar_t)); if (*cant_end_chars != NULL && mbstowcs(*cant_end_chars, ptr, len) == -1) { free (*cant_end_chars); *cant_end_chars = NULL; } /* * Get the spacing flag. I.E. when does a internal newline * get turned into a space. * 1 means all the time. * 0 means only between a multibyte string and * a singlebyte string. */ ptr = CATGETS(cat_fd, 1, 3, "1"); *nl_to_space = atoi(ptr); CATCLOSE(cat_fd); } else #endif { *cant_begin_chars = NULL; *cant_end_chars = NULL; *nl_to_space = 1; } }