diff options
Diffstat (limited to 'Xprint/Oid.c')
-rw-r--r-- | Xprint/Oid.c | 3177 |
1 files changed, 3177 insertions, 0 deletions
diff --git a/Xprint/Oid.c b/Xprint/Oid.c new file mode 100644 index 000000000..3fe926c00 --- /dev/null +++ b/Xprint/Oid.c @@ -0,0 +1,3177 @@ +/* $Xorg: Oid.c,v 1.3 2000/08/17 19:48:06 cpqbld Exp $ */ +/* +(c) Copyright 1996 Hewlett-Packard Company +(c) Copyright 1996 International Business Machines Corp. +(c) Copyright 1996 Sun Microsystems, Inc. +(c) Copyright 1996 Novell, Inc. +(c) Copyright 1996 Digital Equipment Corp. +(c) Copyright 1996 Fujitsu Limited +(c) Copyright 1996 Hitachi, Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the names of the copyright holders shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from said +copyright holders. +*/ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "Oid.h" +#include <X11/Xfuncs.h> /* for memmove */ + +/* + * XpOidNotify value strings + */ +#define NOTIFY_EMAIL_STR "{{event-report-job-completed} electronic-mail}" +#define NOTIFY_NONE_STR "{}" + +#define SafeStrLen(s) ((s) ? strlen((s)) : 0) + +/* + * entry type for the object identifier string map + */ +typedef struct _XpOidStringMapEntry +{ + const char* string; + int length; + int msg_set; + int msg_number; + const char* default_message; + +} XpOidStringMapEntry; + +/* + * include the auto-generated static XpOidStringMap + */ +#include "OidStrs.h" + +/* + * XpOid static function declarations + */ +static XpOid XpOidParse(const char* value_string, + const char** ptr_return); +/* + * XpOidList static function declarations + */ +static XpOidList* XpOidListParse(const char* value_string, + const XpOidList* valid_oids, + const char** ptr_return, int i); + +/* + * XpOidList static function declarations + */ +static XpOidCardList* XpOidCardListParse(const char* value_string, + const XpOidCardList* valid_cards, + const char** ptr_return, int i); + +/* + * XpOidMediumSourceSize static function declarations + */ +static XpOidMediumSS* MediumSSParse(const char* value_string, + const XpOidList* valid_trays, + const XpOidList* valid_medium_sizes, + const char** ptr_return, int i); +static XpOidMediumContinuousSize* MediumContinuousSizeParse(const char*, + const char**); +static void MediumContinuousSizeDelete(XpOidMediumContinuousSize* me); +static XpOidMediumDiscreteSizeList* MediumDiscreteSizeListParse(const char*, + const XpOidList*, + const char**, + int i); +static void MediumDiscreteSizeListDelete(XpOidMediumDiscreteSizeList* list); + +static BOOL ParseArea(const char* value_string, + const char** ptr_return, + XpOidArea* area_return); +static BOOL ParseRealRange(const char* value_string, + const char** ptr_return, + XpOidRealRange* range_return); + +/* + * XpOidTrayMediumList static function declarations + */ +static XpOidTrayMediumList* TrayMediumListParse(const char* value_string, + const XpOidList* valid_trays, + const char** ptr_return, + int i); +static void TrayMediumListValidate(XpOidTrayMediumList* me, + const XpOidMediumSS* msss); + +/* + * XpOidDocFmt + */ +static BOOL XpOidDocFmtNext(XpOidDocFmt* doc_fmt, + const char* value_string, + const char** ptr_return); + +/* + * XpOidDocFmtListParse + */ +static XpOidDocFmtList* XpOidDocFmtListParse(const char* value_string, + const XpOidDocFmtList* valid_fmts, + const char** ptr_return, int i); + +/* + * misc. parsing static function declarations + */ +static BOOL ParseBoolValue(const char* value_string, + const char** ptr_return, + BOOL* bool_return); +static BOOL ParseRealValue(const char* value_string, + const char** ptr_return, + float* real_return); +static BOOL ParseSeqEnd( + const char* value_string, + const char** ptr_return); +static BOOL ParseSeqStart( + const char* value_string, + const char** ptr_return); +static BOOL ParseUnspecifiedValue( + const char* value_string, + const char** ptr_return); +static int SpanToken( + const char* string); +static int SpanWhitespace( + const char* string); + +/* + * String comparison function. + */ +#ifdef HAVE_STRCASECMP +# define StrnCaseCmp(s1, s2, len) strncasecmp(s1, s2, len) +#else +static int StrnCaseCmp(const char *s1, const char *s2, size_t len); +#endif + +/* + * ------------------------------------------------------------------------ + * Name: XpOidString + * + * Description: + * + * Obtain the string representation of an XpOid. + * + * Example: XpOidString(xpoid_copy_count) returns "copy-count". + * + * Return value: + * + * A const pointer to the string. + */ +const char* +XpOidString(XpOid xp_oid) +{ + /* + * XpOid enum values are index values into the string map + */ + return XpOidStringMap[xp_oid].string; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidStringLength + * + * Description: + * + * Obtain the length of the string representation for a given + * XpOid. + * + * Return value: + * + * The string length in bytes. + * + */ +int +XpOidStringLength(XpOid xp_oid) +{ + /* + * XpOid enum values are index values into the string map + */ + return XpOidStringMap[xp_oid].length; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidFromString + * + * Description: + * + * Obtains the XpOid given a string representation of an XpOid. + * + * Example: XpOidFromString("copy-count") returns 'xpoid_copy_count'. + * + * Return value: + * + * The XpOid if successful. 'xpoid_none' if the string pointed to by + * 'value is not recognized or if 'value' is NULL. + */ +XpOid +XpOidFromString(const char* value) +{ + if(value == (const char*)NULL) + return xpoid_none; + else + return XpOidParse(value, (const char**)NULL); +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidParse + * + * Description: + * + * Parse the next whitespace-delimited string from 'value_string' + * updating 'ptr_return' to point to the next unparsed location in + * 'value_string'. 'ptr_return' can be NULL. + * + * Return value: + * + * The corresponding XpOid for the parsed name string. + * A return value of xpoid_none is returned if the parsed name + * was not a valid oid or if no name was found. + * + */ +static XpOid +XpOidParse(const char* value_string, + const char** ptr_return) +{ + const char* ptr; + int length; + int i; + /* + * skip leading whitespace + */ + ptr = value_string + SpanWhitespace(value_string); + /* + * get the whitespace-delimited token length + */ + length = SpanToken(ptr); + /* + * match the oid string in the map + */ + for(i = 0; i < XpOidStringMapCount; i++) + if(length == XpOidStringMap[i].length) + if(strncmp(ptr, XpOidStringMap[i].string, length) == 0) + break; + if(i == XpOidStringMapCount) + i = xpoid_none; + /* + * update the return pointer and return + */ + if(ptr_return != (const char**)NULL) + *ptr_return = ptr+length; + return i; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidListNew + * + * Description: + * + * Creates a new XpOidList initialized from a whitespace-delimited + * list of recognized string representations of oids. The returned + * list will contain only oids found within the passed 'valid_oids' + * XpOidList. + * + * Note: One may notice that in order to create an XpOidList with + * this function, an XpOidList is needed; the 'valid_oids' list + * is often an statically initialized structure. XpOidListInit + * can also be used. + * + * Return value: + * + * NULL if the passed 'value_string' is NULL. + * + * If the list indicated by 'value_string' is empty or contains only + * unrecognized oid string representations, a new XpOidList + * containing zero elements is returned. + * + * If 'valid_oids' is NULL all oids are considered valid. + * + */ +XpOidList* +XpOidListNew(const char* value_string, + const XpOidList* valid_oids) +{ + if(value_string == (const char*)NULL) + return (XpOidList*)NULL; + else + { + const char* ptr; + return XpOidListParse(value_string, valid_oids, &ptr, 0); + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidListDelete + * + * Description: + * + * Frees the memory allocated for 'list'. + * + * Return value: + * + * None. + * + */ +void +XpOidListDelete(XpOidList* list) +{ + if(list != (XpOidList*)NULL) + { + XpOidFree((char*)list->list); + XpOidFree((char*)list); + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidListParse + * + * Description: + * + * This function recursively parses the whitespace-delimited list of + * oid string representations passed via 'value_string'. Oids are + * only added to the resulting list if they are found within the + * passed 'valid_oids' XpOidList. + * + * 'ptr_return' points to a char* variable allocated by the + * caller, and is really only of use during recursion (upon return to + * the original caller, it will point to the end of value_string). + * + * 'value_string' and 'ptr_return' *cannot* be NULL. + * + * Return value: + * + * A newly allocated and initialized XpOidList. + * + * If the list indicated by 'value_string' is empty or contains only + * unrecognized oid string representations, a new XpOidList + * containing zero elements is returned. + * + * If 'valid_oids' is NULL all oids are considered valid. + * + */ +static XpOidList* +XpOidListParse(const char* value_string, + const XpOidList* valid_oids, + const char** ptr_return, + int i) +{ + XpOid oid; + XpOidList* list; + /* + * parse the next valid oid out of the value string + */ + ptr_return = &value_string; + while(1) + { + if(**ptr_return == '\0') + { + /* + * end of value string; stop parsing + */ + oid = xpoid_none; + break; + } + /* + * parse the next oid from the value + */ + oid = XpOidParse(*ptr_return, ptr_return); + if(xpoid_none == oid) + { + /* + * unrecognized oid; keep parsing + */ + continue; + } + if((const XpOidList*)NULL == valid_oids + || + XpOidListHasOid(valid_oids, oid)) + { + /* + * valid oid found; stop parsing + */ + break; + } + } + + if(oid == xpoid_none) + { + /* + * end of value string; allocate the list structure + */ + list = (XpOidList*)XpOidCalloc(1, sizeof(XpOidList)); + list->count = i; + list->list = (XpOid*)XpOidCalloc(i, sizeof(XpOid)); + } + else + { + /* + * recurse + */ + list = XpOidListParse(*ptr_return, valid_oids, ptr_return, i+1); + /* + * set the oid in the list + */ + list->list[i] = oid; + } + /* + * return + */ + return list; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidListHasOid + * + * Description: + * + * Determines if 'oid' is an element of 'list'. + * + * Return value: + * + * xTrue if the oid is found in the list. + * + * xFalse if the oid is not in the list, or if 'list' is NULL. + * + */ +BOOL +XpOidListHasOid(const XpOidList* list, XpOid oid) +{ + int i; + if(list != (XpOidList*)NULL) + for(i = 0; i < list->count; i++) + if(list->list[i] == oid) + return xTrue; + return xFalse; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidListGetIndex + * + * Description: + * + * Returns the array index of 'oid' in 'list' + * + * Return value: + * + * The index of 'oid' in list. + * + * -1 if the oid is not in the list, or if 'list' is NULL. + * + */ +int +XpOidListGetIndex(const XpOidList* list, XpOid oid) +{ + int i; + if(list != (XpOidList*)NULL) + for(i = 0; i < list->count; i++) + if(list->list[i] == oid) + return i; + return -1; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidListString + * + * Description: + * + * Creates a string representation of an XpOidList structure. + * + * Return value: + * + * A newly allocated + * + */ +char* +XpOidListString(const XpOidList* me) +{ + int i; + int length; + char* str; + char* ptr; + /* + * allocate enough memory for the oid string representations, + * including intervening whitespace + */ + for(i = 0, length = 0; i < XpOidListCount(me); i++) + length += XpOidStringLength(XpOidListGetOid(me, i)) + 1; + str = XpOidMalloc(length+1); + /* + * format the list + */ + for(i = 0, ptr = str; i < XpOidListCount(me); i++) +#if defined(sun) && !defined(SVR4) + { + sprintf(ptr, "%s ", XpOidString(XpOidListGetOid(me, i))); + ptr += strlen(ptr); + } +#else + ptr += sprintf(ptr, "%s ", XpOidString(XpOidListGetOid(me, i))); +#endif + /* + * chop trailing whitespace or terminate empty string + */ + str[length] = '\0'; + /* + * return + */ + return str; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidLinkedListNew + * + * Description: + * + * Creates a new instance of an empty XpOidLinkedList. + * + * Return value: + * + * The new XpOidLinkedList. + * + */ +XpOidLinkedList* +XpOidLinkedListNew() +{ + return (XpOidLinkedList*)XpOidCalloc(1, sizeof(XpOidLinkedList)); +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidLinkedListDelete + * + * Description: + * + * Frees the memory allocated for a XpOidLinkedList. + * + * Return value: + * + * None. + * + */ +void +XpOidLinkedListDelete(XpOidLinkedList* me) +{ + if(me != (XpOidLinkedList*)NULL) + { + while(me->head) + { + me->current = me->head; + me->head = me->current->next; + XpOidFree((char*)me->current); + } + XpOidFree((char*)me); + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidLinkedListGetOid + * + * Description: + * + * Retrieves the oid at position 'i' (zero-based) in the + * XpOidLinkedList 'me'. + * + * Return value: + * + * The oid at position 'i'. + * + * xpoid_none if the oid was not found, or the list is empty (or if + * the list contains xpoid_none at position 'i'). + */ +XpOid +XpOidLinkedListGetOid(XpOidLinkedList* me, int i) +{ + if(me == (XpOidLinkedList*)NULL || i < 0 || i >= me->count) + { + return xpoid_none; + } + else + { + me->current = me->head; + while(i--) me->current = me->current->next; + return me->current->oid; + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidLinkedListAddOid + * + * Description: + * + * Adds an oid to the end of an XpOidLinkedList. + * + * Return value: + * + * None. + * + */ +void +XpOidLinkedListAddOid(XpOidLinkedList* me, XpOid oid) +{ + me->current = (XpOidNode)XpOidCalloc(1, sizeof(struct XpOidNodeStruct)); + me->current->oid = oid; + ++me->count; + if(me->tail) + { + me->tail->next = me->current; + me->tail = me->current; + } + else + me->head = me->tail = me->current; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidLinkedListGetIndex + * + * Description: + * + * Returns the position of an oid in a XpOidLinkedList. + * + * Return value: + * + * The zero-based position of 'oid' in the list. + * + * -1 if the oid is not in the list, or if 'me' is NULL. + * + */ +int +XpOidLinkedListGetIndex(XpOidLinkedList* me, XpOid oid) +{ + if((XpOidLinkedList*)NULL != me) + { + int i = 0; + me->current = me->head; + while(me->current) + if(me->current->oid == oid) + { + return i; + } + else + { + ++i; + me->current = me->current->next; + } + } + return -1; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidLinkedListHasOid + * + * Description: + * + * Determines if an oid is an element of a XpOidLinkedList. + * + * Return value: + * + * xTrue if the oid is found in the list. + * + * xFalse if the oid is not in the list, or if 'me' is NULL. + */ +BOOL +XpOidLinkedListHasOid(XpOidLinkedList* me, + XpOid oid) +{ + if((XpOidLinkedList*)NULL != me) + { + me->current = me->head; + while(me->current) + if(me->current->oid == oid) + return xTrue; + else + me->current = me->current->next; + } + return xFalse; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidLinkedListFirstOid + * + * Description: + * + * Positions the XpOidLinkedList 'current' pointer to the first entry + * in the list. + * + * Return value: + * + * The first oid in the list, or xpoid_none if the list NULL or + * empty. + */ +XpOid +XpOidLinkedListFirstOid(XpOidLinkedList* me) +{ + if((XpOidLinkedList*)NULL != me && (me->current = me->head)) + return me->current->oid; + else + return xpoid_none; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidLinkedListNextOid + * + * Description: + * + * Positions the XpOidLinkedList 'current' pointer to the next entry + * in the list. + * + * Return value: + * + * The next oid, or xpoid_none if the end of the list has been + * reached. + */ +XpOid +XpOidLinkedListNextOid(XpOidLinkedList* me) +{ + if(me->current ? me->current = me->current->next : xFalse) + return me->current->oid; + else + return xpoid_none; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidMediumSSNew + * + * Description: + * + * Creates a new XpOidMediumSS initialized from a string value + * specified using the medium-source-sizes syntax. See + * MediumSSParse() below for parsing details. + * + * Return value: + * + * NULL if the passed 'value_string' is NULL, or if a syntax error is + * encountered while parsing the medium-source-sizes value. + * + */ +XpOidMediumSS* +XpOidMediumSSNew(const char* value_string, + const XpOidList* valid_trays, + const XpOidList* valid_medium_sizes) +{ + if(value_string == (const char*)NULL) + return (XpOidMediumSS*)NULL; + else + { + const char* ptr = value_string + SpanWhitespace(value_string); + if(*ptr == '\0') + return (XpOidMediumSS*)NULL; + else + return MediumSSParse(ptr, valid_trays, valid_medium_sizes, + &ptr, 0); + } +} + +/* + * ------------------------------------------------------------------------ + * Name: MediumSSParse + * + * Description: + * + * 'ptr_return' *cannot* be NULL. + * + * + * Return value: + * + * + * + */ +static XpOidMediumSS* +MediumSSParse(const char* value_string, + const XpOidList* valid_trays, + const XpOidList* valid_medium_sizes, + const char** ptr_return, + int i) +{ + XpOidMediumSS* medium_ss; + XpOidMediumSourceSize mss; + /* + * check for the start of a new MediumSourceSize sequence + */ + if(ParseSeqStart(value_string, ptr_return)) + { + /* + * check for an unspecified tray value + */ + if(ParseUnspecifiedValue(*ptr_return, ptr_return)) + mss.input_tray = xpoid_unspecified; + else + { + const char* tray_str; + *ptr_return += SpanWhitespace(*ptr_return); + tray_str = *ptr_return; + /* + * parse out the input tray + */ + mss.input_tray = XpOidParse(*ptr_return, ptr_return); + if((const XpOidList*)NULL != valid_trays + && + !XpOidListHasOid(valid_trays, mss.input_tray) + ) + mss.input_tray = xpoid_none; + if(xpoid_none == mss.input_tray) + { + char* invalid_tray_str; + int len = *ptr_return - tray_str; + if(len > 0) + { + invalid_tray_str = XpOidMalloc(len+1); + strncpy(invalid_tray_str, tray_str, len); + invalid_tray_str[len] = '\0'; + ErrorF("%s\nInvalid tray (%s) found. Will attempt to continue parsing.\n", + XPMSG_WARN_MSS, invalid_tray_str); + XpOidFree(invalid_tray_str); + } + } + } + /* + * attempt to parse a Continuous MediumSize sequence + */ + mss.ms.continuous_size = + MediumContinuousSizeParse(*ptr_return, ptr_return); + if(mss.ms.continuous_size != (XpOidMediumContinuousSize*)NULL) + { + mss.mstag = XpOidMediumSS_CONTINUOUS; + } + else + { + /* + * not continuous, try Discrete MediumSize + */ + mss.ms.discrete = + MediumDiscreteSizeListParse(*ptr_return, valid_medium_sizes, + ptr_return, 0); + if(mss.ms.discrete == (XpOidMediumDiscreteSizeList*)NULL) + { + const char* tray_str; + /* + * syntax error (MediumDiscreteSizeListParse reports error) + */ + switch(mss.input_tray) + { + case xpoid_none: + tray_str = "an invalid"; + break; + case xpoid_unspecified: + tray_str = "default (tray specifier omitted)"; + break; + default: + tray_str = XpOidString(mss.input_tray); + break; + } + ErrorF("%s\nError occurred while parsing medium sizes for %s tray.\n", + XPMSG_WARN_MSS, tray_str); + return NULL; + } + mss.mstag = XpOidMediumSS_DISCRETE; + } + /* + * parse out the MediumSourceSize sequence end + */ + if(!ParseSeqEnd(*ptr_return, ptr_return)) + { + /* + * syntax error + */ + ErrorF("%s\nSequence End expected. Unparsed data: %s\n", + XPMSG_WARN_MSS, *ptr_return); + return NULL; + } + /* + * recurse to parse the next MediumSourceSize sequence + */ + medium_ss = MediumSSParse(*ptr_return, + valid_trays, valid_medium_sizes, + ptr_return, + xpoid_none == mss.input_tray ? i : i+1); + if(medium_ss == (XpOidMediumSS*)NULL + || + xpoid_none == mss.input_tray) + { + /* + * syntax error or invalid tray - clean up + */ + switch(mss.mstag) + { + case XpOidMediumSS_CONTINUOUS: + MediumContinuousSizeDelete(mss.ms.continuous_size); + break; + case XpOidMediumSS_DISCRETE: + MediumDiscreteSizeListDelete(mss.ms.discrete); + break; + } + if(medium_ss == (XpOidMediumSS*)NULL) + /* + * syntax error - return + */ + return NULL; + } + if(xpoid_none != mss.input_tray) + { + /* + * copy the current MediumSourceSize into the array + */ + memmove((medium_ss->mss)+i, &mss, sizeof(XpOidMediumSourceSize)); + } + } + else + { + /* + * MediumSourceSize sequence start not found + */ + if(**ptr_return == '\0') + { + if(0 == i) + { + ErrorF("%s\nNo valid trays found.\n", XPMSG_WARN_MSS); + return NULL; + } + /* + * end of value string; allocate the MediumSS structure + */ + medium_ss = (XpOidMediumSS*)XpOidCalloc(1, sizeof(XpOidMediumSS)); + medium_ss->count = i; + medium_ss->mss = (XpOidMediumSourceSize*) + XpOidCalloc(i, sizeof(XpOidMediumSourceSize)); + } + else + { + /* + * syntax error + */ + ErrorF("%s\nSequence Start expected.\nunparsed data: %s\n", + XPMSG_WARN_MSS, *ptr_return); + return NULL; + } + } + return medium_ss; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidMediumSSDelete + * + * Description: + * + * + * + * Return value: + * + * + * + */ +void +XpOidMediumSSDelete(XpOidMediumSS* me) +{ + if(me != (XpOidMediumSS*)NULL) + { + int i; + for(i = 0; i < me->count; i++) + { + switch((me->mss)[i].mstag) + { + case XpOidMediumSS_CONTINUOUS: + MediumContinuousSizeDelete((me->mss)[i].ms.continuous_size); + break; + case XpOidMediumSS_DISCRETE: + MediumDiscreteSizeListDelete((me->mss)[i].ms.discrete); + break; + } + } + XpOidFree((char*)me); + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidMediumSSHasSize + * + * Description: + * + * + * + * Return value: + * + * + * + */ +BOOL +XpOidMediumSSHasSize(XpOidMediumSS* me, XpOid page_size) +{ + int i_mss, i_ds; + XpOidMediumDiscreteSizeList* ds_list; + + if(me != (XpOidMediumSS*)NULL && page_size != xpoid_none) + for(i_mss = 0; i_mss < me->count; i_mss++) + { + switch((me->mss)[i_mss].mstag) + { + case XpOidMediumSS_DISCRETE: + ds_list = (me->mss)[i_mss].ms.discrete; + for(i_ds = 0; i_ds < ds_list->count; i_ds++) + if(page_size == (ds_list->list)[i_ds].page_size) + return xTrue; + break; + + case XpOidMediumSS_CONTINUOUS: + /* + * unsupported + */ + break; + } + } + /* + * return + */ + return xFalse; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidMediumSSString + * + * Description: + * + * Creates a string representation of an XpOidMediumSS structure. + * + * Return value: + * + * A newly allocated + * + */ +char* XpOidMediumSSString(const XpOidMediumSS* me) +{ + int itray, isize; + int valid_size_count; + int length; + char* str; + char* ptr; + XpOidMediumDiscreteSize* ds; + char buf[128]; + /* + * determine the size of the string representation + */ + for(itray = 0, length = 0; itray < XpOidMediumSSCount(me); itray++) + { + if(xpoid_none == me->mss[itray].input_tray + || + XpOidMediumSS_CONTINUOUS == me->mss[itray].mstag) + { + /* + * skip invalid tray or unsupported continuous size spec + */ + continue; + } + for(isize = 0, valid_size_count = 0; + isize < me->mss[itray].ms.discrete->count; + isize++) + { + ds = me->mss[itray].ms.discrete->list+isize; + if(ds->page_size == xpoid_none) + continue; + ++valid_size_count; + length += XpOidStringLength(ds->page_size); + length += ds->long_edge_feeds ? 4 : 5; /* "True" or "False" */ +#if defined(sun) && !defined(SVR4) + sprintf(buf, "{%.4f %.4f %.4f %.4f}", + ds->assured_reproduction_area.minimum_x, + ds->assured_reproduction_area.maximum_x, + ds->assured_reproduction_area.minimum_y, + ds->assured_reproduction_area.maximum_y); + length += strlen(buf); +#else + length += sprintf(buf, "{%.4f %.4f %.4f %.4f}", + ds->assured_reproduction_area.minimum_x, + ds->assured_reproduction_area.maximum_x, + ds->assured_reproduction_area.minimum_y, + ds->assured_reproduction_area.maximum_y); +#endif + length += 5; /* "{<size> <feed> <area>} " */ + } + if(valid_size_count == 0) + { + /* + * no valid sizes, skip + */ + continue; + } + if(xpoid_unspecified == me->mss[itray].input_tray) + length += 2; /* "''" */ + else + length += XpOidStringLength(me->mss[itray].input_tray); + length += 4; /* "{<tray> <sizes>} " */ + } + /* + * allocate + */ + str = XpOidMalloc(length+1); + /* + * format + */ + for(itray = 0, ptr = str; itray < XpOidMediumSSCount(me); itray++) + { + if(xpoid_none == me->mss[itray].input_tray + || + XpOidMediumSS_CONTINUOUS == me->mss[itray].mstag) + { + /* + * skip invalid tray or unsupported continuous size spec + */ + continue; + } + /* + * check to ensure all of the specified sizes are valid + */ + for(isize = 0, valid_size_count = 0; + isize < me->mss[itray].ms.discrete->count; + isize++) + { + ds = me->mss[itray].ms.discrete->list+isize; + if(ds->page_size != xpoid_none) + ++valid_size_count; + } + if(valid_size_count == 0) + { + /* + * no valid sizes, skip + */ + continue; + } + + if(xpoid_unspecified == me->mss[itray].input_tray) + { +#if defined(sun) && !defined(SVR4) + sprintf(ptr, "{'' "); + ptr += strlen(ptr); +#else + ptr += sprintf(ptr, "{'' "); +#endif + } + else + { +#if defined(sun) && !defined(SVR4) + sprintf(ptr, "{%s ", XpOidString(me->mss[itray].input_tray)); + ptr += strlen(ptr); +#else + ptr += sprintf(ptr, "{%s ", + XpOidString(me->mss[itray].input_tray)); +#endif + } + for(isize = 0; isize < me->mss[itray].ms.discrete->count; isize++) + { + ds = me->mss[itray].ms.discrete->list+isize; + if(ds->page_size != xpoid_none) +#if defined(sun) && !defined(SVR4) + { + sprintf(ptr, "{%s %s {%.4f %.4f %.4f %.4f}} ", + XpOidString(ds->page_size), + ds->long_edge_feeds ? "True" : "False", + ds->assured_reproduction_area.minimum_x, + ds->assured_reproduction_area.maximum_x, + ds->assured_reproduction_area.minimum_y, + ds->assured_reproduction_area.maximum_y); + ptr += strlen(ptr); + } +#else + ptr += sprintf(ptr, "{%s %s {%.4f %.4f %.4f %.4f}} ", + XpOidString(ds->page_size), + ds->long_edge_feeds ? "True" : "False", + ds->assured_reproduction_area.minimum_x, + ds->assured_reproduction_area.maximum_x, + ds->assured_reproduction_area.minimum_y, + ds->assured_reproduction_area.maximum_y); +#endif + } +#if defined(sun) && !defined(SVR4) + sprintf(ptr, "} "); + ptr += strlen(ptr); +#else + ptr += sprintf(ptr, "} "); +#endif + } + /* + * chop trailing whitespace or terminate empty string + */ + str[length] = '\0'; + /* + * return + */ + return str; +} + +/* + * ------------------------------------------------------------------------ + * Name: MediumContinuousSizeParse + * + * Description: + * + * 'ptr_return' *cannot* be NULL. + * + * + * Return value: + * + * + * + */ +static XpOidMediumContinuousSize* +MediumContinuousSizeParse(const char* value_string, + const char** ptr_return) +{ + const char* first_nonws_ptr; + XpOidMediumContinuousSize* mcs = NULL; + /* + * skip leading whitespace + */ + first_nonws_ptr = value_string + SpanWhitespace(value_string); + /* + * parse out the MediumSize sequence start char + */ + if(!ParseSeqStart(first_nonws_ptr, ptr_return)) + goto MediumContinuousSizeParse_error; + /* + * peek ahead to see if it looks like we actually have a continuous + * size spec (looking for the sequence start char on the 1st range spec) + */ + if(!ParseSeqStart(*ptr_return, (const char**)NULL)) + goto MediumContinuousSizeParse_error; + /* + * Ok, let's go for it + */ + mcs = (XpOidMediumContinuousSize*) + XpOidCalloc(1, sizeof(XpOidMediumContinuousSize)); + /* + * "range across the feed direction" + */ + if(!ParseRealRange(*ptr_return, ptr_return, &mcs->range_across_feed)) + goto MediumContinuousSizeParse_error; + /* + * "increment across the feed direction" (optional, default 0) + */ + if(!ParseUnspecifiedValue(*ptr_return, ptr_return)) + if(!ParseRealValue(*ptr_return, ptr_return, + &mcs->increment_across_feed)) + goto MediumContinuousSizeParse_error; + /* + * "range in the feed direction" + */ + if(!ParseRealRange(*ptr_return, ptr_return, &mcs->range_in_feed)) + goto MediumContinuousSizeParse_error; + /* + * "increment in the feed direction" (optional, default 0) + */ + if(!ParseUnspecifiedValue(*ptr_return, ptr_return)) + if(!ParseRealValue(*ptr_return, ptr_return, + &mcs->increment_in_feed)) + goto MediumContinuousSizeParse_error; + /* + * "long edge feeds" flag (default TRUE) + */ + if(ParseUnspecifiedValue(*ptr_return, ptr_return)) + mcs->long_edge_feeds = xTrue; + else + if(!ParseBoolValue(*ptr_return, ptr_return, &mcs->long_edge_feeds)) + goto MediumContinuousSizeParse_error; + /* + * "generic assured reproduction area" + */ + if(!ParseArea(*ptr_return, ptr_return, &mcs->assured_reproduction_area)) + goto MediumContinuousSizeParse_error; + /* + * parse out the MediumSize sequence end character + */ + if(!ParseSeqEnd(*ptr_return, ptr_return)) + goto MediumContinuousSizeParse_error; + /* + * return + */ + return mcs; + + + MediumContinuousSizeParse_error: + /* + * syntax error - don't log since this function may be called + * as a lookahead + */ + *ptr_return = first_nonws_ptr; + XpOidFree((char*)mcs); + return NULL; +} + +/* + * ------------------------------------------------------------------------ + * Name: MediumContinuousSizeDelete + * + * Description: + * + * 'ptr_return' *cannot* be NULL. + * + * + * Return value: + * + * + * + */ +static void +MediumContinuousSizeDelete(XpOidMediumContinuousSize* me) +{ + XpOidFree((char*)me); +} + +/* + * ------------------------------------------------------------------------ + * Name: MediumDiscreteSizeListParse + * + * Description: + * + * 'ptr_return' *cannot* be NULL. + * + * Return value: + * + * + * + */ +static XpOidMediumDiscreteSizeList* +MediumDiscreteSizeListParse(const char* value_string, + const XpOidList* valid_medium_sizes, + const char** ptr_return, + int i) +{ + XpOidMediumDiscreteSizeList* list; + XpOidMediumDiscreteSize mds; + /* + * check for the start of a new MediumSize sequence + */ + if(ParseSeqStart(value_string, ptr_return)) + { + /* + * "page size" + */ + mds.page_size = XpOidParse(*ptr_return, ptr_return); + if((const XpOidList*)NULL != valid_medium_sizes + && + !XpOidListHasOid(valid_medium_sizes, mds.page_size) + ) + mds.page_size = xpoid_none; + /* + * "long edge feeds" flag (default TRUE) + */ + if(ParseUnspecifiedValue(*ptr_return, ptr_return)) + mds.long_edge_feeds = xTrue; + else + if(!ParseBoolValue(*ptr_return, ptr_return, + &mds.long_edge_feeds)) + { + /* + * syntax error + */ + ErrorF("%s\nBoolean expected.\nunparsed data: %s\n", + XPMSG_WARN_MSS, *ptr_return); + return (XpOidMediumDiscreteSizeList*)NULL; + } + /* + * "assured reproduction area" + */ + if(!ParseArea(*ptr_return, ptr_return, + &mds.assured_reproduction_area)) + { + /* + * syntax error + */ + ErrorF("%s\nArea specification error.\nunparsed data: %s\n", + XPMSG_WARN_MSS, *ptr_return); + return (XpOidMediumDiscreteSizeList*)NULL; + } + /* + * parse out the MediumSize sequence end character + */ + if(!ParseSeqEnd(*ptr_return, ptr_return)) + { + ErrorF("%s\nSequence End expected. Unparsed data: %s\n", + XPMSG_WARN_MSS, *ptr_return); + return (XpOidMediumDiscreteSizeList*)NULL; + } + /* + * recurse to parse the next Discrete MediumSize sequence + */ + if(mds.page_size == xpoid_none) + { + list = MediumDiscreteSizeListParse(*ptr_return, valid_medium_sizes, + ptr_return, i); + } + else + { + list = MediumDiscreteSizeListParse(*ptr_return, valid_medium_sizes, + ptr_return, i+1); + if(list != (XpOidMediumDiscreteSizeList*)NULL) + { + /* + * copy the current discrete MediumSize into the list + */ + memmove((list->list)+i, &mds, sizeof(XpOidMediumDiscreteSize)); + } + } + } + else + { + /* + * MediumSize sequence start not found; end of the discrete sizes + * list + */ + if(0 == i) + { + ErrorF("%s\nNo valid medium sizes found for tray.\n", + XPMSG_WARN_MSS); + return (XpOidMediumDiscreteSizeList*)NULL; + } + list = (XpOidMediumDiscreteSizeList*) + XpOidCalloc(1, sizeof(XpOidMediumDiscreteSizeList)); + list->count = i; + list->list = (XpOidMediumDiscreteSize*) + XpOidCalloc(i, sizeof(XpOidMediumDiscreteSize)); + } + return list; +} + +/* + * ------------------------------------------------------------------------ + * Name: MediumDiscreteSizeListDelete + * + * Description: + * + * + * + * Return value: + * + * + * + */ +static void +MediumDiscreteSizeListDelete(XpOidMediumDiscreteSizeList* list) +{ + if(list != (XpOidMediumDiscreteSizeList*)NULL) + { + XpOidFree((char*)list->list); + XpOidFree((char*)list); + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidTrayMediumListNew + * + * Description: + * + * Only need the valid trays; validation requires bumping up against + * msss using TrayMediumListValidate; this needs valid trays + * because of unspecified trays ion msss, but + * TrayMediumListValidate will take care of invalid sizes... + * + * Return value: + * + * + * + */ +XpOidTrayMediumList* +XpOidTrayMediumListNew(const char* value_string, + const XpOidList* valid_trays, + const XpOidMediumSS* msss) +{ + if(value_string == (const char*)NULL) + return (XpOidTrayMediumList*)NULL; + else + { + const char* ptr; + XpOidTrayMediumList* me; + me = TrayMediumListParse(value_string, valid_trays, &ptr, 0); + if((XpOidTrayMediumList*)NULL != me) + TrayMediumListValidate(me, msss); + return me; + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidTrayMediumListDelete + * + * Description: + * + * + * + * Return value: + * + * + * + */ +void +XpOidTrayMediumListDelete(XpOidTrayMediumList* list) +{ + if(list != (XpOidTrayMediumList*)NULL) + { + XpOidFree((char*)list->list); + XpOidFree((char*)list); + } +} + +/* + * ------------------------------------------------------------------------ + * Name: TrayMediumListParse + * + * Description: + * + * 'ptr_return' *cannot* be NULL. + * + * Return value: + * + * + * + */ +static XpOidTrayMediumList* +TrayMediumListParse(const char* value_string, + const XpOidList* valid_trays, + const char** ptr_return, int i) +{ + XpOidTrayMedium tm; + XpOidTrayMediumList* list; + /* + * check for the start of a new InputTrayMedium sequence + */ + if(ParseSeqStart(value_string, ptr_return)) + { + /* + * "input tray" + */ + tm.input_tray = XpOidParse(*ptr_return, ptr_return); + if((XpOidList*)NULL != valid_trays + && + !XpOidListHasOid(valid_trays, tm.input_tray) + ) + tm.input_tray = xpoid_none; + /* + * "medium" + */ + tm.medium = XpOidParse(*ptr_return, ptr_return); + /* + * parse out the InputTrayMedium sequence end character + */ + if(!ParseSeqEnd(*ptr_return, ptr_return)) + { + ErrorF("%s\n", XPMSG_WARN_ITM); + return NULL; + } + /* + * recurse to parse the next InputTrayMedium sequence + */ + list = TrayMediumListParse(*ptr_return, valid_trays, ptr_return, i+1); + if(list != (XpOidTrayMediumList*)NULL) + { + /* + * copy the current InputTrayMedium into the list + */ + memmove((list->list)+i, &tm, sizeof(XpOidTrayMedium)); + } + } + else + { + /* + * InputTrayMedium sequence start not found + */ + if(**ptr_return == '\0') + { + /* + * end of the list + */ + list = (XpOidTrayMediumList*) + XpOidCalloc(1, sizeof(XpOidTrayMediumList)); + list->count = i; + list->list = (XpOidTrayMedium*) + XpOidCalloc(i, sizeof(XpOidTrayMedium)); + } + else + { + /* + * syntax error + */ + ErrorF("%s\n", XPMSG_WARN_ITM); + return NULL; + } + } + /* + * return + */ + return list; +} + +/* + * ------------------------------------------------------------------------ + * Name: TrayMediumListValidate + * + * Description: + * + * Validate the input-trays-medium list based on a passed + * medium-source-sizes-supported structure. The validated + * input-trays-medium list will have the same number of entries upon + * return from this function. Invalid entries are indicated by + * setting the tray specification to xpoid_none. + * + * Return value: + * + * None. + * + */ +static void +TrayMediumListValidate(XpOidTrayMediumList* me, + const XpOidMediumSS* msss) +{ + int i_mss, i_ds, i_itm; + XpOidMediumDiscreteSizeList* ds_list; + int tray_count; + XpOid current_tray, current_medium; + XpOidMediumDiscreteSizeList* unspecified_tray_ds; + XpOidMediumDiscreteSizeList* tray_ds; + + if(msss == (XpOidMediumSS*)NULL + || + me == (XpOidTrayMediumList*)NULL) + { + return; + } + /* + * loop through the input trays medium list + */ + for(i_itm = 0; i_itm < XpOidTrayMediumListCount(me); i_itm++) + { + current_tray = XpOidTrayMediumListTray(me, i_itm); + if(current_tray == xpoid_none) + continue; + current_medium = XpOidTrayMediumListMedium(me, i_itm); + if(current_medium == xpoid_none) + { + /* + * no medium; invalidate this entry + */ + me->list[i_itm].input_tray = xpoid_none; + continue; + } + /* + * loop through the MediumSourceSizes, looking for an appropriate + * discrete sizes spec for the current tray + */ + unspecified_tray_ds = (XpOidMediumDiscreteSizeList*)NULL; + tray_ds = (XpOidMediumDiscreteSizeList*)NULL; + for(i_mss = 0; + i_mss < msss->count && + tray_ds == (XpOidMediumDiscreteSizeList*)NULL; + i_mss++) + { + switch((msss->mss)[i_mss].mstag) + { + case XpOidMediumSS_DISCRETE: + if((msss->mss)[i_mss].input_tray == current_tray) + tray_ds = (msss->mss)[i_mss].ms.discrete; + else if((msss->mss)[i_mss].input_tray == xpoid_unspecified) + unspecified_tray_ds = (msss->mss)[i_mss].ms.discrete; + break; + + case XpOidMediumSS_CONTINUOUS: + /* + * unsupported + */ + break; + } + } + /* + * if the tray was not matched, use the unspecified tray size + * list + */ + if(tray_ds == (XpOidMediumDiscreteSizeList*)NULL) + if(unspecified_tray_ds == (XpOidMediumDiscreteSizeList*)NULL) + { + /* + * not even an unspecified tray, invalidate this + * input-trays-medium entry. + */ + me->list[i_itm].input_tray = xpoid_none; + continue; + } + else + tray_ds = unspecified_tray_ds; + /* + * loop through the discrete sizes list, looking for a size that + * matches the medium for the current input tray + */ + for(i_ds = 0; i_ds < tray_ds->count; i_ds++) + { + /* + * check to see if the current input tray's medium size + * matches the current discrete size + * + * Note: in the CDEnext SI, medium identifiers coincide with + * medium-size identifiers. If the DP-Medium object is + * ever implemented, this check would need to be + * changed so that the input tray's medium size is + * obtained from the indicated Medium object, and not + * inferred from the medium identifier itself. + */ + if((tray_ds->list)[i_ds].page_size == current_medium) + { + /* + * The current input tray's medium size matches the + * current discrete medium size. + */ + break; + } + } + if(i_ds == tray_ds->count) + { + /* + * The current input tray's medium size was not found in the + * discrete size list; mark the input tray medium entry + * invalid + */ + me->list[i_itm].input_tray = xpoid_none; + } + + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidTrayMediumListString + * + * Description: + * + * Creates a string representation of an XpOidTrayMediumList structure. + * + * Return value: + * + * A newly allocated + * + */ +char* XpOidTrayMediumListString(const XpOidTrayMediumList* me) +{ + int i; + int length; + char* str; + char* ptr; + XpOid tray; + /* + * allocate enough memory for the string representation, + * including intervening delimiters and whitespace + */ + for(i = 0, length = 0; i < XpOidTrayMediumListCount(me); i++) + { + tray = XpOidTrayMediumListTray(me, i); + if(xpoid_none != tray) + { + length += XpOidStringLength(tray); + length += XpOidStringLength(XpOidTrayMediumListMedium(me, i)); + length += 4; + } + } + str = XpOidMalloc(length+1); + /* + * format the list + */ + for(i = 0, ptr = str; i < XpOidTrayMediumListCount(me); i++) + { + tray = XpOidTrayMediumListTray(me, i); + if(xpoid_none != tray) + { +#if defined(sun) && !defined(SVR4) + sprintf(ptr, "{%s %s} ", + XpOidString(tray), + XpOidString(XpOidTrayMediumListMedium(me, i))); + ptr += strlen(ptr); +#else + ptr += sprintf(ptr, "{%s %s} ", + XpOidString(tray), + XpOidString(XpOidTrayMediumListMedium(me, i))); +#endif + } + } + /* + * chop trailing whitespace or terminate empty string + */ + str[length] = '\0'; + /* + * return + */ + return str; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidTrayMediumListHasTray + * + * Description: + * + * Determines if 'tray' is found in 'list'. + * + * Return value: + * + * xTrue if the tray is found in the list. + * + * xFalse if the tray is not in the list, or if 'list' is NULL. + * + */ +BOOL +XpOidTrayMediumListHasTray(const XpOidTrayMediumList* list, XpOid tray) +{ + int i; + if(list != (XpOidTrayMediumList*)NULL && tray != xpoid_none) + for(i = 0; i < list->count; i++) + if(XpOidTrayMediumListTray(list, i) == tray) + return xTrue; + return xFalse; +} + +/* + * ------------------------------------------------------------------------ + * Name: ParseArea + * + * Description: + * + * Skips leading whitespace and parses out and returns a XpOidArea. + * + * Return value: + * + * xTrue if the XpOidArea was successfully parsed. ptr_return is + * updated to point to location where the parsing ended. + * + * xFalse if a XpOidArea was not found; ptr_return is updated + * to point to the first non-whitespace char in value_string. + * + */ +static BOOL +ParseArea(const char* value_string, + const char** ptr_return, + XpOidArea* area_return) +{ + const char* first_nonws_ptr; + const char* ptr; + /* + * skip leading whitespace + */ + first_nonws_ptr = value_string + SpanWhitespace(value_string); + /* + * parse out the area sequence start + */ + if(!ParseSeqStart(first_nonws_ptr, &ptr)) + goto ParseArea_error; + /* + * parse the minimum x value + */ + if(!ParseRealValue(ptr, &ptr, + area_return ? &area_return->minimum_x : NULL)) + goto ParseArea_error; + /* + * parse the maximum x value + */ + if(!ParseRealValue(ptr, &ptr, + area_return ? &area_return->maximum_x : NULL)) + goto ParseArea_error; + /* + * parse the minimum y value + */ + if(!ParseRealValue(ptr, &ptr, + area_return ? &area_return->minimum_y : NULL)) + goto ParseArea_error; + /* + * parse the maximum y value + */ + if(!ParseRealValue(ptr, &ptr, + area_return ? &area_return->maximum_y : NULL)) + goto ParseArea_error; + /* + * parse out the area sequence end + */ + if(!ParseSeqEnd(ptr, &ptr)) + goto ParseArea_error; + /* + * update the return pointer + */ + if(ptr_return != (const char**)NULL) + *ptr_return = ptr; + /* + * return + */ + return xTrue; + + + ParseArea_error: + /* + * syntax error + */ + if(ptr_return != (const char**)NULL) + *ptr_return = first_nonws_ptr; + return xFalse; +} + +/* + * ------------------------------------------------------------------------ + * Name: ParseRealRange + * + * Description: + * + * Skips leading whitespace and parses out and returns a + * XpOidRealRange. + * + * Return value: + * + * xTrue if the XpOidRealRange was successfully + * parsed. ptr_return is updated to point to location where the + * parsing ended. + * + * xFalse if a XpOidRealRange was not found; ptr_return is + * updated to point to the first non-whitespace char in value_string. + * + */ +static BOOL +ParseRealRange(const char* value_string, + const char** ptr_return, + XpOidRealRange* range_return) +{ + const char* first_nonws_ptr; + const char* ptr; + /* + * skip leading whitespace + */ + first_nonws_ptr = value_string + SpanWhitespace(value_string); + /* + * parse out the range sequence start + */ + if(!ParseSeqStart(first_nonws_ptr, &ptr)) + goto ParseRealRange_error; + /* + * parse the lower bound + */ + if(!ParseRealValue(ptr, &ptr, + range_return ? &range_return->lower_bound : NULL)) + goto ParseRealRange_error; + /* + * parse the upper bound + */ + if(!ParseRealValue(ptr, &ptr, + range_return ? &range_return->upper_bound : NULL)) + goto ParseRealRange_error; + /* + * parse out the range sequence end + */ + if(!ParseSeqEnd(ptr, &ptr)) + goto ParseRealRange_error; + /* + * update the return pointer + */ + if(ptr_return != (const char**)NULL) + *ptr_return = ptr; + /* + * return + */ + return xTrue; + + + ParseRealRange_error: + /* + * syntax error + */ + if(ptr_return != (const char**)NULL) + *ptr_return = first_nonws_ptr; + return xFalse; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidNotifyParse + * + * Description: + * + * + * Return value: + * + * + */ +XpOidNotify XpOidNotifyParse(const char* value_string) +{ + const char* ptr = value_string; + + if(value_string == (const char*)NULL) + return XPOID_NOTIFY_NONE; + /* + * look for an event handling profile sequence start + */ + if(!ParseSeqStart(value_string, &ptr)) + { + if('\0' == *ptr) + /* + * empty value is valid + */ + return XPOID_NOTIFY_NONE; + else + return XPOID_NOTIFY_UNSUPPORTED; + } + /* + * look for an event set sequence start + */ + if(!ParseSeqStart(ptr, &ptr)) + { + /* + * check for an empty event handling profile + */ + if(ParseSeqEnd(ptr, &ptr)) + { + ptr += SpanWhitespace(ptr); + if(*ptr == '\0') + /* + * valid empty event handling profile sequence + */ + return XPOID_NOTIFY_NONE; + } + return XPOID_NOTIFY_UNSUPPORTED; + } + /* + * the only event in the set should be report job completed + */ + if(xpoid_val_event_report_job_completed != XpOidParse(ptr, &ptr)) + return XPOID_NOTIFY_UNSUPPORTED; + /* + * event set sequence end + */ + if(!ParseSeqEnd(ptr, &ptr)) + return XPOID_NOTIFY_UNSUPPORTED; + /* + * delivery method of electronic mail + */ + if(xpoid_val_delivery_method_electronic_mail != XpOidParse(ptr, &ptr)) + return XPOID_NOTIFY_UNSUPPORTED; + /* + * event handling profile sequence end + */ + if(!ParseSeqEnd(ptr, &ptr)) + return XPOID_NOTIFY_UNSUPPORTED; + /* + * end of value + */ + ptr += SpanWhitespace(ptr); + if('\0' == *ptr) + /* + * valid supported notification profile + */ + return XPOID_NOTIFY_EMAIL; + else + return XPOID_NOTIFY_UNSUPPORTED; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidNotifyString + * + * Description: + * + * + * Return value: + * + * + */ +const char* XpOidNotifyString(XpOidNotify notify) +{ + switch(notify) + { + case XPOID_NOTIFY_UNSUPPORTED: + return (const char*)NULL; + break; + case XPOID_NOTIFY_NONE: + return NOTIFY_NONE_STR; + break; + case XPOID_NOTIFY_EMAIL: + return NOTIFY_EMAIL_STR; + break; + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidDocFmtNew + * + * Description: + * + * + * Return value: + * + * + */ +XpOidDocFmt* +XpOidDocFmtNew(const char* value_string) +{ + XpOidDocFmt* doc_fmt; + const char* ptr; + + if((const char*)NULL == value_string) + return (XpOidDocFmt*)NULL; + ptr = value_string + SpanWhitespace(value_string); + if('\0' == *ptr) + return (XpOidDocFmt*)NULL; + /* + * get the document format from the value string + */ + doc_fmt = (XpOidDocFmt*)XpOidCalloc(1, sizeof(XpOidDocFmt)); + if(xTrue == XpOidDocFmtNext(doc_fmt, ptr, &ptr)) + { + /* + * verify that the document format is the only value specified + */ + ptr += SpanWhitespace(ptr); + if('\0' == *ptr) + /* + * valid document-format value + */ + return doc_fmt; + } + /* + * invalid + */ + XpOidDocFmtDelete(doc_fmt); + ErrorF("%s\n", XPMSG_WARN_DOC_FMT); + return (XpOidDocFmt*)NULL; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidDocFmtDelete + * + * Description: + * + * + * Return value: + * + * + */ +void +XpOidDocFmtDelete(XpOidDocFmt* doc_fmt) +{ + if((XpOidDocFmt*)NULL != doc_fmt) + { + XpOidFree(doc_fmt->format); + XpOidFree(doc_fmt->variant); + XpOidFree(doc_fmt->version); + XpOidFree(doc_fmt); + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidDocFmtString + * + * Description: + * + * + * Return value: + * + * + */ +char* +XpOidDocFmtString(XpOidDocFmt* doc_fmt) +{ + if((XpOidDocFmt*)NULL != doc_fmt) + { + if((char*)NULL != doc_fmt->format) + { + char* str = XpOidMalloc(1+SafeStrLen(doc_fmt->format)+ + 1+SafeStrLen(doc_fmt->variant)+ + 1+SafeStrLen(doc_fmt->version)+ + 1+1); + sprintf(str, "{%s %s %s}", doc_fmt->format, + (char*)NULL != doc_fmt->variant ? doc_fmt->variant : "", + (char*)NULL != doc_fmt->version ? doc_fmt->version : ""); + return str; + } + } + return (char*)NULL; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidDocFmtNext + * + * Description: + * + * Assumes non-NULL value string. + * + * Return value: + * + * + */ +static BOOL +XpOidDocFmtNext(XpOidDocFmt* doc_fmt, + const char* value_string, + const char** ptr_return) +{ + const char* ptr; + const char* first_nonws_ptr; + const char* format; + const char* variant; + const char* version; + int format_len; + int variant_len; + int version_len; + /* + * skip leading whitespace + */ + ptr = value_string + SpanWhitespace(value_string); + first_nonws_ptr = ptr; + /* + * sequence start + */ + if(!ParseSeqStart(ptr, &ptr)) + goto XpOidDocFmtNext_error; + /* + * skip whitepace to the start of the document format, and save the + * location + */ + ptr += SpanWhitespace(ptr); + format = ptr; + /* + * document format + */ + if(0 == (format_len = SpanToken(ptr))) + goto XpOidDocFmtNext_error; + ptr += format_len; + /* + * optional variant + */ + ptr += SpanWhitespace(ptr); + variant = ptr; + if(0 != (variant_len = SpanToken(ptr))) + { + ptr += variant_len; + /* + * optional version + */ + ptr += SpanWhitespace(ptr); + version = ptr; + version_len = SpanToken(ptr); + ptr += version_len; + } + else + version_len = 0; + /* + * sequence end + */ + if(!ParseSeqEnd(ptr, &ptr)) + goto XpOidDocFmtNext_error; + /* + * update return pointer + */ + if((const char**)NULL != ptr_return) + *ptr_return = ptr; + /* + * update the passed document format struct + */ + memset(doc_fmt, 0, sizeof(XpOidDocFmt)); + doc_fmt->format = XpOidMalloc(format_len+1); + strncpy(doc_fmt->format, format, format_len); + doc_fmt->format[format_len] = '\0'; + if(0 < variant_len) + { + doc_fmt->variant = XpOidMalloc(variant_len+1); + strncpy(doc_fmt->variant, variant, variant_len); + doc_fmt->variant[variant_len] = '\0'; + if(0 < version_len) + { + doc_fmt->version = XpOidMalloc(version_len+1); + strncpy(doc_fmt->version, version, version_len); + doc_fmt->version[version_len] = '\0'; + } + } + return xTrue; + + XpOidDocFmtNext_error: + if((const char**)NULL != ptr_return) + *ptr_return = first_nonws_ptr; + return xFalse; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidDocFmtListNew + * + * Description: + * + * + * Return value: + * + * + */ +XpOidDocFmtList* +XpOidDocFmtListNew(const char* value_string, + const XpOidDocFmtList* valid_fmts) +{ + if((char*)NULL != value_string) + { + const char* ptr; + return XpOidDocFmtListParse(value_string, valid_fmts, &ptr, 0); + } + return (XpOidDocFmtList*)NULL; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidDocFmtListDelete + * + * Description: + * + * + * Return value: + * + * + */ +void +XpOidDocFmtListDelete(XpOidDocFmtList* list) +{ + if((XpOidDocFmtList*)NULL != list) + { + int i; + for(i = 0; i < list->count; i++) + { + XpOidFree(list->list[i].format); + XpOidFree(list->list[i].variant); + XpOidFree(list->list[i].version); + } + XpOidFree(list->list); + XpOidFree(list); + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidDocFmtListString + * + * Description: + * + * Assumes the passed structure is valid. + * + * Return value: + * + * + */ +char* +XpOidDocFmtListString(const XpOidDocFmtList* list) +{ + if((XpOidDocFmtList*)NULL != list) + { + if(0 < list->count) + { + int i; + int str_len; + char* str; + char* ptr; + /* + * allocate the return string + */ + for(i = 0, str_len = 0; i < list->count; i++) + { + str_len += + 1 + SafeStrLen(list->list[i].format) + + 1 + SafeStrLen(list->list[i].variant) + + 1 + SafeStrLen(list->list[i].version) + 2; + } + str = XpOidMalloc(str_len+1); + /* + * print the list into the string and return it + */ + ptr = str; + for(i = 0; i < list->count; i++) + { + XpOidDocFmt* df = &list->list[i]; + +#if defined(sun) && !defined(SVR4) + sprintf(ptr, "{%s %s %s} ", + df->format, + (char*)NULL != df->variant ? df->variant : "", + (char*)NULL != df->version ? df->version : ""); + ptr += strlen(ptr); +#else + ptr += + sprintf(ptr, "{%s %s %s} ", + df->format, + (char*)NULL != df->variant ? df->variant : "", + (char*)NULL != df->version ? df->version : ""); +#endif + } + return str; + } + } + return (char*)NULL; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidDocFmtListParse + * + * Description: + * + * Assumes the passed value_string and ptr_return are non-NULL. + * + * Return value: + * + * + */ +static XpOidDocFmtList* +XpOidDocFmtListParse(const char* value_string, + const XpOidDocFmtList* valid_fmts, + const char** ptr_return, + int i) +{ + XpOidDocFmt doc_fmt; + XpOidDocFmtList* list; + BOOL status; + /* + * get the next document-format from the value string, skipping + * values not found in the passed list of valid formats + */ + *ptr_return = value_string; + while((status = XpOidDocFmtNext(&doc_fmt, *ptr_return, ptr_return)) + && + (const XpOidDocFmtList*)NULL != valid_fmts + && + !XpOidDocFmtListHasFmt(valid_fmts, &doc_fmt) + ); + + if(xFalse == status) + { + if('\0' == **ptr_return) + { + if(0 == i) + { + /* + * empty value string + */ + return (XpOidDocFmtList*)NULL; + } + else + { + /* + * done parsing; allocate the list and return + */ + list = + (XpOidDocFmtList*)XpOidCalloc(1, sizeof(XpOidDocFmtList)); + list->count = i; + list->list = (XpOidDocFmt*)XpOidCalloc(i, sizeof(XpOidDocFmt)); + return list; + } + } + else + { + /* + * invalid document format + */ + ErrorF("%s\n", XPMSG_WARN_DOCFMT_LIST); + return (XpOidDocFmtList*)NULL; + } + } + else + { + /* + * recurse to parse remaining document formats + */ + list = XpOidDocFmtListParse(*ptr_return, valid_fmts, ptr_return, i+1); + if((XpOidDocFmtList*)NULL != list) + { + /* + * add this doc fmt to the list + */ + list->list[i].format = doc_fmt.format; + list->list[i].variant = doc_fmt.variant; + list->list[i].version = doc_fmt.version; + } + return list; + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidDocFmtListHasFmt + * + * Description: + * + * Assumes the passed structure is valid. + * + * Return value: + * + * + */ +BOOL +XpOidDocFmtListHasFmt(const XpOidDocFmtList* list, + const XpOidDocFmt* fmt) +{ + int i; + if(list != (XpOidDocFmtList*)NULL + && + fmt != (XpOidDocFmt*)NULL + && + fmt->format != (char*)NULL + ) + { + for(i = 0; i < list->count; i++) + { + /* + * formats must match + */ + if(strcmp(fmt->format, list->list[i].format) != 0) + continue; + /* + * variants must both be NULL or match + */ + if(fmt->variant == (char*)NULL) + if(list->list[i].variant == (char*)NULL) + return xTrue; + else + continue; + if(list->list[i].variant == (char*)NULL) + continue; + if(strcmp(fmt->variant, list->list[i].variant) != 0) + continue; + /* + * versions must both be NULL or match + */ + if(fmt->version == (char*)NULL) + if(list->list[i].version == (char*)NULL) + return xTrue; + else + continue; + if(list->list[i].version == (char*)NULL) + continue; + if(strcmp(fmt->version, list->list[i].version) == 0) + return xTrue; + } + } + return xFalse; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidCardListNew + * + * Description: + * + * + * Return value: + * + * + */ +XpOidCardList* +XpOidCardListNew(const char* value_string, const XpOidCardList* valid_cards) +{ + if((const char*)NULL != value_string) + { + const char* ptr; + + return XpOidCardListParse(value_string, valid_cards, &ptr, 0); + } + else + return (XpOidCardList*)NULL; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidCardListDelete + * + * Description: + * + * + * Return value: + * + * + */ +void +XpOidCardListDelete(XpOidCardList* list) +{ + if((XpOidCardList*)NULL != list) + { + XpOidFree(list->list); + XpOidFree(list); + } +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidCardListString + * + * Description: + * + * + * Return value: + * + * + */ +char* +XpOidCardListString(const XpOidCardList* list) +{ + if((XpOidCardList*)NULL != list) + { + char buf[48]; + int str_len; + char* str; + int i; + char* ptr; + /* + * allocate the output string + */ + for(i = 0, str_len = 0; i < list->count; i++) +#if defined(sun) && !defined(SVR4) + { + sprintf(buf, "%lu", list->list[i]) + 1; + str_len += strlen(buf); + } +#else + str_len += sprintf(buf, "%lu", list->list[i]) + 1; +#endif + str = XpOidMalloc(str_len+1); + /* + * write the list to the string + */ + for(i = 0, ptr = str; i < list->count; i++) +#if defined(sun) && !defined(SVR4) + { + sprintf(ptr, "%lu ", list->list[i]); + ptr += strlen(ptr); + } +#else + ptr += sprintf(ptr, "%lu ", list->list[i]); +#endif + return str; + } + else + return (char*)NULL; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidCardListHasCard + * + * Description: + * + * Determines if 'card' is an element of 'list'. + * + * Return value: + * + * xTrue if the card is found in the list. + * + * xFalse if the card is not in the list, or if 'list' is NULL. + * + */ +BOOL +XpOidCardListHasCard(const XpOidCardList* list, unsigned long card) +{ + int i; + if(list != (XpOidCardList*)NULL) + for(i = 0; i < list->count; i++) + if(list->list[i] == card) + return xTrue; + return xFalse; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidCardListParse + * + * Description: + * + * Assumes the passed value_string and ptr_return are non-NULL. + * + * Return value: + * + * + */ +static XpOidCardList* +XpOidCardListParse(const char* value_string, + const XpOidCardList* valid_cards, + const char** ptr_return, + int i) +{ + unsigned long card; + XpOidCardList* list; + BOOL status; + + /* + * get the next card from the value string, skipping values not + * found in the passed list of valid cards + */ + *ptr_return = value_string; + while((status = XpOidParseUnsignedValue(*ptr_return, ptr_return, &card)) + && + (const XpOidCardList*)NULL != valid_cards + && + !XpOidCardListHasCard(valid_cards, card) + ); + + if(xFalse == status) + { + if('\0' == **ptr_return) + { + if(0 == i) + { + /* + * empty value string + */ + return (XpOidCardList*)NULL; + } + else + { + /* + * done parsing; allocate the list and return + */ + list = (XpOidCardList*)XpOidCalloc(1, sizeof(XpOidCardList)); + list->count = i; + list->list = + (unsigned long*)XpOidCalloc(i, sizeof(unsigned long)); + return list; + } + } + else + { + /* + * parsing error + */ + ErrorF("%s\n", XPMSG_WARN_CARD_LIST); + return (XpOidCardList*)NULL; + } + } + else + { + /* + * recurse to parse remaining cardinal values + */ + list = XpOidCardListParse(*ptr_return, valid_cards, ptr_return, i+1); + if((XpOidCardList*)NULL != list) + { + /* + * add this value to the list + */ + list->list[i] = card; + } + return list; + } +} + +/* + * ------------------------------------------------------------------------ + * Name: ParseBoolValue + * + * Description: + * + * + * Return value: + * + * + */ +static BOOL +ParseBoolValue(const char* value_string, + const char** ptr_return, + BOOL* bool_return) +{ + const char* ptr; + int length; + BOOL status; + /* + * skip leading whitespace + */ + ptr = value_string + SpanWhitespace(value_string); + /* + * get the whitespace-delimited token length + */ + length = SpanToken(ptr); + /* + * determine if true or false or bad + */ + if(StrnCaseCmp(ptr, "TRUE", length) == 0) + { + if(bool_return != (BOOL*)NULL) + *bool_return = xTrue; + status = xTrue; + } + else if(StrnCaseCmp(ptr, "FALSE", length) == 0) + { + if(bool_return != (BOOL*)NULL) + *bool_return = xFalse; + status = xTrue; + } + else + { + /* + * syntax error + */ + status = xFalse; + } + /* + * update the return pointer and return + */ + if(ptr_return != (const char**)NULL) + *ptr_return = status ? ptr+length : ptr; + return status; +} + +/* + * ------------------------------------------------------------------------ + * Name: XpOidParseUnsignedValue + * + * Description: + * + * Skips leading whitespace and parses out and returns a unsigned number. + * + * Return value: + * + * xTrue if a unsigned number was successfully parsed. ptr_return is + * updated to point to location where the unsigned number parsing + * ended. + * + * xFalse if a unsigned number was not found; ptr_return is updated + * to point to the first non-whitespace char in value_string. + * + */ +BOOL +XpOidParseUnsignedValue(const char* value_string, + const char** ptr_return, + unsigned long* unsigned_return) +{ + long value; + BOOL status; + const char* first_nonws_ptr; + const char* ptr; + /* + * skip leading whitespace + */ + first_nonws_ptr = value_string + SpanWhitespace(value_string); + value = strtol(first_nonws_ptr, (char**)(&ptr), 0); + if(ptr == first_nonws_ptr || value < 0) + status = xFalse; + else + status = xTrue; + /* + * update return parms + */ + if(ptr_return != (const char**)NULL) + *ptr_return = ptr; + if(unsigned_return != (unsigned long*)NULL) + *unsigned_return = (unsigned long)value; + /* + * return + */ + return status; +} + +/* + * ------------------------------------------------------------------------ + * Name: ParseRealValue + * + * Description: + * + * Skips leading whitespace and parses out and returns a real number. + * + * Return value: + * + * xTrue if a real number was successfully parsed. ptr_return is + * updated to point to location where the real number parsing + * ended. + * + * xFalse if a real number was not found; ptr_return is updated + * to point to the first non-whitespace char in value_string. + * + */ +static BOOL +ParseRealValue(const char* value_string, + const char** ptr_return, + float* real_return) +{ + float real_value; + BOOL status; + const char* first_nonws_ptr; + const char* ptr; + /* + * skip leading whitespace + */ + first_nonws_ptr = value_string + SpanWhitespace(value_string); + real_value = (float)strtod(first_nonws_ptr, (char**)(&ptr)); + if(ptr == first_nonws_ptr) + status = xFalse; + else + status = xTrue; + /* + * update return parms + */ + if(ptr_return != (const char**)NULL) + *ptr_return = ptr; + if(real_return != (float*)NULL) + *real_return = real_value; + /* + * return + */ + return status; +} + +/* + * ------------------------------------------------------------------------ + * Name: ParseSeqEnd + * + * Description: + * + * Description: + * + * Skips leading whitespace and parses out the sequence end + * character '}'. + * + * Return value: + * + * xTrue if the sequence end character was parsed; ptr_return is + * updated to point to the first char following the sequence end + * character. + * + * xFalse if the sequence end character was not found; ptr_return is + * updated to point to the first non-whitespace char in value_string. + * + */ +static BOOL +ParseSeqEnd(const char* value_string, + const char** ptr_return) +{ + const char* ptr; + BOOL status; + /* + * skip leading whitespace + */ + ptr = value_string + SpanWhitespace(value_string); + /* + * parse out the sequence end character + */ + if(*ptr == '}') + { + status = xTrue; + ++ptr; + } + else + status = xFalse; + /* + * update the return pointer + */ + if(ptr_return != (const char**)NULL) + *ptr_return = ptr; + /* + * return + */ + return status; +} + +/* + * ------------------------------------------------------------------------ + * Name: ParseSeqStart + * + * Description: + * + * Skips leading whitespace and parses out the sequence start + * character '{'. + * + * Return value: + * + * xTrue if the sequence start character was parsed; ptr_return is + * updated to point to the first char following the sequence start + * character. + * + * xFalse if the sequence start character was not found; ptr_return is + * updated to point to the first non-whitespace char in value_string. + * + */ +static BOOL +ParseSeqStart(const char* value_string, + const char** ptr_return) +{ + const char* ptr; + BOOL status; + /* + * skip leading whitespace + */ + ptr = value_string + SpanWhitespace(value_string); + /* + * parse out the sequence start character + */ + if(*ptr == '{') + { + status = xTrue; + ++ptr; + } + else + status = xFalse; + /* + * update the return pointer + */ + if(ptr_return != (const char**)NULL) + *ptr_return = ptr; + /* + * return + */ + return status; +} + +/* + * ------------------------------------------------------------------------ + * Name: ParseUnspecifiedValue + * + * Description: + * + * Skips leading whitespace and parses out an unspecified optional + * value (i.e. matching '' or "" - skips all data between the set of + * quotes). + * + * Return value: + * + * xTrue if an unspecified value was parsed; ptr_return is updated to + * point to the first char following the trailing quote. + * + * xFalse if an unspecified value was not found; ptr_return is updated + * to point to the first non-whitespace char in value_string. + * + */ +static BOOL +ParseUnspecifiedValue(const char* value_string, + const char** ptr_return) +{ + BOOL status; + const char* ptr; + /* + * skip leading whitespace + */ + ptr = value_string + SpanWhitespace(value_string); + /* + * parse out an unspecified optional value ('' or "") + */ + if(*ptr == '\'' || *ptr == '"') + { + char delim[2]; + + if(ptr_return != (const char**)NULL) + { + delim[0] = *ptr; + delim[1] = '\0'; + /* + * skip over the matching delimiter + */ + ++ptr; + ptr += strcspn(ptr, delim); + if(*ptr != '\0') + ++ptr; + } + status = xTrue; + } + else + status = xFalse; + /* + * update the return pointer + */ + if(ptr_return != (const char**)NULL) + *ptr_return = ptr; + /* + * return + */ + return status; +} + +/* + * ------------------------------------------------------------------------ + * Name: SpanToken + * + * Description: + * + * Returns the length of the initial segment of the passed string + * that consists entirely of non-whitespace and non-sequence + * delimiter characters. + * + * + */ +static int +SpanToken(const char* string) +{ + const char* ptr; + for(ptr = string; + *ptr != '\0' && !isspace(*ptr) && *ptr != '{' && *ptr != '}'; + ++ptr); + return ptr - string; +} + +/* + * ------------------------------------------------------------------------ + * Name: SpanWhitespace + * + * Description: + * + * Returns the length of the initial segment of the passed string + * that consists entirely of whitespace characters. + * + * + */ +static int +SpanWhitespace(const char* string) +{ + const char* ptr; + for(ptr = string; *ptr != '\0' && isspace(*ptr); ++ptr); + return ptr - string; +} + +#ifndef HAVE_STRCASECMP +/* + * ------------------------------------------------------------------------ + * Name: StrnCaseCmp + * + * Description: + * + * Implements strncasecmp() for those platforms that need it. + * + * + */ +static int +StrnCaseCmp(const char *s1, const char *s2, size_t len) +{ + char c1, c2; + int result; + + while (len--) + { + c1 = *s1++; + c2 = *s2++; + result = tolower(c1) - tolower(c2); + + if (result != 0) + return result; + } + + return 0; +} +#endif |