cdesktopenv/cde/lib/DtHelp/FormatUtil.c

843 lines
21 KiB
C

/*
* 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 librararies 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 <ctype.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <X11/Xos.h>
#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 <nl_types.h>
#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 = str;
else if (*str == '\n') {
token = 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;
}
}