⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stringhandling.c

📁 PGP8.0源码 请认真阅读您的文件包然后写出其具体功能
💻 C
字号:
/*______________________________________________________________________________
	Copyright (C) 2002 PGP Corporation
	All rights reserved.


	$Id: StringHandling.c,v 1.7 2002/09/09 00:31:43 sdas Exp $
______________________________________________________________________________*/

/*::: MODULE OVERVIEW :::::::::::::
Provides various string-handling services.

--- revision history --------
7/2/01 Version 1.2: Paul Ryan
+ extended module to handle version comparison
+ documentation enhancement

8/26/99 Version 1.1: Paul Ryan
+ integrated standard LibLinkList functionality
+ documentation adjustment

1/9/99 Version 1.0: Paul Ryan
::::::::::::::::::::::::::::::::::::*/

#include "StringHandling.h"


char  epc_ALPHALWR[] = "abcdefghijklmnopqrstuvwxyz", 
		epc_ALPHAUPR[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 
		epc_NUM10[] = "0123456789", epc_NUMHEX[] = "0123456789abcdefABCDEF", 
		epc_ALPHANUMLWR[] = "abcdefghijklmnopqrstuvwxyz0123456789", 
		epc_ALPHANUMUPR[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 
		epc_ALPHANUM[] = "abcdefghijklmnopqrstuvwxyz"
							"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 
		ec_DOT = '.';


#define mi_MAXLEN_CMP  64


/** ei_verCmp( ***
Compares typical dot-notation version strings to determine their relative 
order, in a manner similar to the standard strcmp() function. Comparisons are 
not sensitive to case. Version strings are expected to be in the format 
#[A][.#[A]][.#[A]]... where #'s are decimal numerals and A's are alphabetic 
characters. Tolerance for invalidly formatted strings is strict, though not 
perfectly strict when a clear comparison decision is available. (What is 
"clear" the developer must discern for herself by trial & error.)

--- parameters & return ----
pc_CMP: Version string to be compared with the model version string.
pc_MDL: The model version string to be compared against.
pi: Address of integer variable in which the comparison result will be stored. 
	Result is less than zero if pc_CMP < pc_MDL, zero if pc_CMP = pc_MDL, 
	greater than zero if pc_CMP > pc_MDL. A null string involved in the 
	comparison is considered to be lexicographically the least possible.
RETURN:
	eus_ERR_INVLD_ARG if a parameter is obviously invalid
	eus_SUCCESS if comparison succeeded

--- revision history -------
7/2/01 PR: created			*/
int ei_verCmp( const char  pc_CMP[],
				const char  pc_MDL[], 
				int *const  pi)	{
	//static for speed
	static const char  pc_ZERO[] = "0";

	//static for speed
	static char  pc_okChrs[ sizeof( epc_ALPHANUMLWR) + 1], 
					pc_2Dots[ sizeof( ec_DOT) * 2 + 1];

	unsigned int  ui_lenCmp, ui_lenMdl;
	char  pc_mdl[ mi_MAXLEN_CMP], pc_cmp[ mi_MAXLEN_CMP], * pc_c, * pc_m, 
			* pc_cnx = NULL, * pc_mnx = NULL, * pc_ca, * pc_ma;
	int  i;

	//initialize the result to indicate that the compare version is equivalent 
	//	to the model version
	*pi = ei_SAME;

	//the first time thru, initialize utility strings
	if (!*pc_okChrs)	{
		strcpy( pc_okChrs, epc_ALPHANUMLWR);
		pc_okChrs[ sizeof( epc_ALPHANUMLWR) - 1] = ec_DOT;
		memset( pc_2Dots, ec_DOT, sizeof( ec_DOT) * 2);
	}

	//if any input is obviously invalid, short-circuit with failure
	if (!( pi && pc_CMP && pc_MDL && (ui_lenCmp = strlen( pc_CMP)) < 
								mi_MAXLEN_CMP && !strstr( pc_CMP, pc_2Dots) && 
								strspn( strlwr( strcpy( pc_cmp, pc_CMP)), 
								pc_okChrs) == ui_lenCmp && (ui_lenMdl = 
								strlen( pc_MDL)) < mi_MAXLEN_CMP && !strstr( 
								pc_MDL, pc_2Dots) && strspn( strlwr( strcpy( 
								pc_mdl, pc_MDL)), pc_okChrs) == ui_lenMdl))
		return eus_ERR_INVLD_ARG;

	//if the first component of the compare version string is not null...
	if (*pc_cmp)	{
		//if the component is obviously invalid, short-circuit with failure
		if (!strchr( epc_NUM10, *pc_cmp) || *pc_cmp == '0' && strchr( 
													epc_NUM10, *(pc_cmp + 1)))
			return eus_ERR_INVLD_ARG;
		if (pc_cnx = strchr( pc_cmp, ec_DOT))
			*pc_cnx = (char) NULL;
		if ((pc_ca = _strspnp( pc_cmp, epc_NUM10)) && _strspnp( pc_ca + 1, 
																epc_ALPHALWR))
			return eus_ERR_INVLD_ARG;

		//get rid of any trailing dot in the string
		if (*(pc_cmp + ui_lenCmp - 1) == ec_DOT)
			*(pc_cmp + --ui_lenCmp) = (char) NULL;
	} //if (*pc_cmp)

	//if the first counterpart component is not null...
	if (*pc_mdl)	{
		//if the component is obviously invalid, short-circuit with failure
		if (!strchr( epc_NUM10, *pc_mdl) || *pc_mdl == '0' && strchr( 
													epc_NUM10, *(pc_mdl + 1)))
			return eus_ERR_INVLD_ARG;
		if (pc_mnx = strchr( pc_mdl, ec_DOT))
			*pc_mnx = (char) NULL;
		if ((pc_ma = _strspnp( pc_mdl, epc_NUM10)) && _strspnp( pc_ma + 1, 
																epc_ALPHALWR))
			return eus_ERR_INVLD_ARG;

		//get rid of any trailing dot in the string
		if (*(pc_mdl + ui_lenMdl - 1) == ec_DOT)
			*(pc_mdl + --ui_lenMdl) = (char) NULL;
	} //if (*pc_mdl)

	//if the entire version strings are the same, declare so and short-circuit
	if (ui_lenCmp == ui_lenMdl && memcmp( pc_cmp, pc_mdl, ui_lenCmp) == ei_SAME)
		return eus_SUCCESS;

	//work through the component pairs within the version strings, from major 
	//	to minor...
	pc_m = *pc_mdl ? pc_mdl : NULL;
	pc_c = *pc_cmp ? pc_cmp : NULL;
	do	{
		//if both version strings have been fully analyzed with no effective 
		//	difference found, declare them equivalent and stop analyzing
		if (!( pc_c || pc_m))
			break;

		//if the compare version string has been fully analyzed...
		if (!pc_c)	{
			//if the model version string component is not zero, declare the 
			//	compare version string to be less than the model string and 
			//	stop analyzing
			if (strcmp( pc_m, pc_ZERO) != ei_SAME)	{
				*pi = ei_SAME - 1;
				break;
			}
		//else if the model version string has been fully analyzed...
		}else if (!pc_m)	{
			//if the compare version string component is not zero, declare the 
			//	compare version string to be greater than the model string and 
			//	stop analyzing
			if (strcmp( pc_c, pc_ZERO) != ei_SAME)	{
				*pi = ei_SAME + 1;
				break;
			}
		//Else our mode must still be one-to-one comparison. So if the compare 
		//	component is not equivalent to its counterpart, relay its greater- 
		//	or less-than status and stop analyzing.
		}else if ((i = strcmp( pc_c, pc_m)) != ei_SAME)	{
			*pi = i;
			break;
		} //if (!pc_c)

		//if the model version string has a further compare component to 
		//	analyze...
		if (pc_cnx)	{
			//move to it
			pc_c = pc_cnx + 1;

			//if the component is invalid, short-circuit with failure
			if (!strchr( epc_NUM10, *pc_c) || *pc_c == '0' && strchr( 
														epc_NUM10, *(pc_c + 1)))
				return eus_ERR_INVLD_ARG;
			if (pc_cnx = strchr( pc_c, ec_DOT))
				*pc_cnx = (char) NULL;
			if ((pc_ca = _strspnp( pc_c, epc_NUM10)) && _strspnp( pc_ca + 
															1, epc_ALPHALWR))
				return eus_ERR_INVLD_ARG;
		//else note that we've reached the end of the compare version string
		}else
			pc_c = NULL;

		//if the model version string has a further minor component to 
		//	analyze...
		if (pc_mnx)	{
			//move to it
			pc_m = pc_mnx + 1;

			//if the component is invalid, short-circuit with failure
			if (!strchr( epc_NUM10, *pc_m) || *pc_m == '0' && strchr( 
														epc_NUM10, *(pc_m + 1)))
				return eus_ERR_INVLD_ARG;
			if (pc_mnx = strchr( pc_m, ec_DOT))
				*pc_mnx = (char) NULL;
			if ((pc_ma = _strspnp( pc_m, epc_NUM10)) && _strspnp( pc_ma + 1, 
																epc_ALPHALWR))
				return eus_ERR_INVLD_ARG;
		//else note that we've reached the end of the model version string
		}else
			pc_m = NULL;
	} while (TRUE);

	return eus_SUCCESS;
} //ei_verCmp(


/** e_FreeStringArray( ***


--- parameters ----------


--- revision history ----
8/26/99 PR: documentation adjustment
1/5/99 PR: created		*/
//DOC!!
void e_FreeStringArray( char * * *const  pppc, 
						const unsigned long  ul_ELEMENTS)	{
	char * * ppc = *pppc;

	if (!pppc)
		return;

	e_FreeStringArrayElements( ppc, ul_ELEMENTS);

	//free the array pointer itself
	free( ppc);

	//nullify the array pointer to assist the caller in not using it anymore
	*pppc = NULL;
} //e_FreeStringArray(


/** e_FreeStringArrayElements( ***


--- parameters ---------


--- revision history ---
1/5/99 PR: created		*/
//DOC!!
void e_FreeStringArrayElements( char * *const  ppc, 
								const unsigned long  ul_ELEMENTS)	{
	unsigned long  ul;

	if (!ppc)
		return;

	//free each string within the array
	for (ul = 0; ul < ul_ELEMENTS; ul++)
		if (ppc[ ul])	{
			free( ppc[ ul]);
			ppc[ ul] = NULL;
		}
} //e_FreeStringArrayElements(


/** ef_AddStringNodeFifo( ***


--- parameters & return ----

RETURN: TRUE if no error occurred; FALSE otherwise

--- revision history -------
8/26/99 PR: integration of standard LibLinkList functionality
1/11/99 PR: created			*/
//DOC!!
BOOL ef_AddStringNodeFifo( char *const  pc_orig, 
							const BOOL  f_COPY, 
							StringNode * *const  ppt_nd)	{
	char * pc;

	if (!( pc_orig && ppt_nd))
		return FALSE;

	//according to the caller's request, either transfer control of the 
	//	string to the just-created node or allocate new space for the string 
	//	and copy it in
	if (!ef_AddListNodeFifo( pc = f_COPY ? malloc( strlen( pc_orig) + 1) : 
														pc_orig, ppt_nd))	{
		if (f_COPY)
			free( pc);
		return FALSE;
	}
	if (f_COPY)
		strcpy( (*ppt_nd)->pc, pc_orig);

	return TRUE;
} //ef_AddStringNodeFifo(


/** ef_AddStringNodeFifoUnique( ***
Purpose is to append a given string to the end of a given list, provided that 
that string is not already in the list.

--- parameters & return -----
pc: pointer to the string to append to the list if it's not already there
f_COPY: flag telling whether a copy of the string (pc) should be stored, 
	instead of the string itself
f_CASE_SENSITIVE: flag telling whether uniqueness should be determined on a 
	case-sensitive or -insensitive basis
ppt: Input & Output. Pointer to the _head_ node pointer in the list to be 
	appended to. If a node is added, the node pointer returned will point to 
	the added node, else the node pointer will be null to indicate that the 
	string was not unique to the list.
RETURN: TRUE if no error occurred; FALSE if memory is insufficient to add the 
	string node

--- suggested enhancement ---
8/26/99 PR: extend procedure so it can be used on a case-insensitive basis

--- revision history --------
8/26/99 PR: created			*/
BOOL ef_AddStringNodeFifoUnique( char *const  pc, 
									const BOOL  f_COPY, 
									const BOOL  f_CASE_SENSITIVE, 
									StringNode * *const  ppt)	{
	StringNode * pt_nd, * pt;

	if (!( pc && ppt))
		return FALSE;

	pt_nd = *ppt;
	*ppt = NULL;

	if (ef_ListContainsString( pc, pt_nd, f_CASE_SENSITIVE))
		return TRUE;

	//according to the caller's request, either transfer control of the 
	//	string to the just-created node or allocate new space for the string 
	//	and copy it in
	pt = pt_nd;
	if (!ef_AddStringNodeFifo( pc, f_COPY, &pt))
		return FALSE;
	if (!pt_nd)
		pt_nd = pt;

	*ppt = pt;

	return TRUE;
} //ef_AddStringNodeFifoUnique(


/** epc_strtokStrict( ***
Behaves as the standard strtok() function does, except that leading 
delimiters are not skipped but instead return a null string. Thus this 
procedure behaves more along the lines of a "split" function.

--- parameters & return ----
pc_refresh: Pointer to the source string to be searched for the next 
	delimiter. If provided, string will be preserved statically and ensuing 
	tokens obtained by specifying this parameter as NULL.
pc_DELIM: pointer to the string of one-character delimiters to use in parsing 
	the source string
RETURN: Pointer to the next token in the source string. NULL if no further 
	tokens are available in the source string or if no source string has been 
	statically stored by the procedure.

--- revision history -------
8/26/99 PR: created			*/
const char * epc_strtokStrict( char *const  pc_refresh, 
								const char  pc_DELIM[])	{
	static char * pc_src;

	const char * pc, * pc_ret = NULL;
	char * pc_end;

	if (!( pc_DELIM && (pc_refresh || pc_src)))
		return NULL;

	if (pc_refresh)
		pc_src = pc_refresh;

	pc = pc_DELIM;
	do	{
		if (!(pc_end = strchr( pc_src, *pc)))
			continue;

		*pc_end = (char) NULL;
		pc_ret = pc_src;
		pc_src = pc_end + 1;
		break;
	} while (*++pc);

	if (!*pc)	{
		pc_ret = pc_src;
		pc_src = NULL;
	}

	return pc_ret;
} //epc_strtokStrict(


/** ef_ListContainsString( ***
Returns whether a string list includes a given string.

--- parameters & return ----
PC: pointer to the string to be sought for within the list
pt: pointer to the head node of the list to be searched
f_CASE_SENSITIVE: flag telling whether uniqueness should be determined on a 
	case-sensitive or -insensitive basis
RETURN: TRUE if list contains string; FALSE otherwise

--- revision history -------
8/26/99 PR
+ extended procedure to accommodate case-insensitive comparisons
+ completed documentation

1/9/99 PR: created			*/
BOOL ef_ListContainsString( const char  PC[], 
							const StringNode * pt, 
							const BOOL  f_CASE_SENSITIVE)	{
	if (!( PC && pt))
		return FALSE;

	do
		if (pt->pc)
			if ( (f_CASE_SENSITIVE ? strcmp( PC, pt->pc) : 
											stricmp( PC, pt->pc)) == ei_SAME)
				return TRUE;
	while (pt = pt->pt_next);

	return FALSE;
} //ef_ListContainsString(


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -