/* ** COPYRIGHT (c) 1991 BY ** DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS. ** ALL RIGHTS RESERVED. ** ** THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED ** ONLY IN ACCORDANCE OF THE TERMS OF SUCH LICENSE AND WITH THE ** INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER ** COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY ** OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY ** TRANSFERRED. ** ** THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE ** AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT ** CORPORATION. ** ** DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS ** SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. */ /* **++ ** Facility: ** ** PSE (C-based) String Facility ** ** Version: X1.0 ** ** Abstract: ** ** This module contains the public interface of the PSE (C-based) ** String Facility. ** ** The PSE String Facility has two objectives. First, to provide a robust ** string facility for C programmers -- in particular, one that does ** memory management. Second, to provide a string facility that ** interfaces easily with the VMS programming environment -- in ** particular, one that provides VMS string descriptors. ** ** The PSE String Facility defines the PSE_STRING data type. It is a VMS ** string descriptor, either fixed or dynamic. Hence, objects of this ** type can be passed directly to VMS routines. The PSE String Facility ** obeys the VMS string descriptor semantics -- it automatically allocates ** and deallocates memory as appropriate for dynamic strings. When you are ** done with a dynamic string, you should free it using PSE_STR_FREE. ** ** The PSE String Facility also makes it easy to convert between ** PSE_STRINGs and ASCIZ strings. Routines exist which make PSE string ** copies of ASCIZ strings. Other routines make ASCIZ string copies of ** PSE strings. The function ASCIZ provides a ASCIZ version of a PSE ** string on-the-fly, so that, for example, you can write: ** ** printf( "%s\n", asciz( name_string ) ); ** ** Limitations: ** ** Currently, there is no inverse of the ASCIZ function. Limitations of ** the C language seem to provide no elegant way of writing such a ** function. There is the considerably less elegant PSE_STR_CONVERT_ASCIZ ** macro. ** ** Such a function would have the side effect of making it easy to include ** literal strings in PSE_STR_xxx routine calls. For example, one could ** write: ** status = pse_str_equal( name_string, string( "abc" ) ); ** ** This is a significant short-coming. I challenge all you C hackers to ** come up with a solution to this problem. ** ** Currently, the PSE String Facility does not contain routines that ** do substring searching and modification. I intend to add a complete ** set of such routines as soon as the need and/or the will appears. ** ** Author: ** Mark Arsenault, Technical Languages and Environments, CRL Project ** ** Creation Date: 29-Jul-91 ** ** Questions for Reviewers: ** Can we create macros for many routines which will allow the user to ** use either string descriptors or literal strings as input ** parameters (like _COPY_STRING etcetera in XBLISS)? ** ** ** Modification History: ** X1.0-1 MEA 6-Sep-91 Add PSE_STR_APPEND_F and PSE_STR_COPY_F. ** X1.0-2 MEA 20-Sep-91 PSE_STR_COPY_RAW **-- */ /* Ignore multiple includes in C programs. */ #ifndef pse_str__def #define pse_str__def 1 /* ** Primitive Types */ typedef unsigned short int pse_str_length; typedef char *pse_str_pointer; typedef char *pse_str_asciz; /* ** PSE_STR_CLASS - The class of the string descriptor. ** ** This enumerated type indicates the class of a string descriptor. ** Only fixed and dynamic descriptors are defined. */ typedef enum { pse_c_str_class_fixed = 1, pse_c_str_class_dynamic, } pse_str_class; /* ** PSE_STRING - A PSE string descriptor. ** ** Users should treat this as an opaque type. Use PSE_STR_GET_LENGTH and ** PSE_STR_GET_POINTER to get detailed information about strings. */ typedef struct { pse_str_length length; unsigned char type; unsigned char class; pse_str_pointer pointer; } pse_string; /* ** String Initialization ** ** Here's an example of the definition of a dynamic string. ** ** pse_string name = pse_str_dynamic; ** ** Here's an example of the definition of a literal string. ** ** static pse_string library = pse_str_constant( "pse$library" ); */ #define pse_str_fixed { 0, 14, (unsigned char) pse_c_str_class_fixed, 0 } #define pse_str_dynamic { 0, 14, (unsigned char) pse_c_str_class_dynamic, 0 } #define pse_str_constant(s) \ { sizeof(s) - 1, 14, (unsigned char) pse_c_str_class_fixed, s } /* ** String Initialization Work-arounds ** ** Unfortunately, the following initialization ** ** pse_string name = pse_str_dynamic; ** ** results in (bogus) portability messages using VAXC. As a work-around ** do the following instead. ** ** pse_string name; ** . ** . ** . ** name = pse_g_str_dynamic; ** ** The following definitions should be changed to globals when VAXC fixes ** releases its fixed EXTERN implementation. */ static pse_string pse_g_str_fixed = pse_str_fixed; static pse_string pse_g_str_dynamic = pse_str_dynamic; /* ** PSE_STR_CONVERT_ASCIZ - Call a routine converting ASCIZ string to PSE_STRING. ** ** This macro makes it easy to create PSE_STRINGs whose life-time is ** a routine call. For example, using this macro, the following code ** sequence: ** ** { ** pse_string string; ** string = pse_g_str_fixed; ** pse_str_describe_asciz( &string, asciz_str ); ** str$downcase( &other_str, &string ); ** } ** ** can be written as: ** ** pse_str_convert_asciz(asciz_str, pse_str_upcase(&other_str, &_string)); ** ** The first parameter is the ASCIZ string of which you need an PSE_STRING ** version. The second parameter is the routine call, or any sequence which ** the C preprocessor will interpret as a parameter. For example, you can ** write: ** ** pse_str_convert_asciz(asciz_str, status = pse_str_compare(&x, &_string)); ** ** Use the token ASCIZ_STRING to indicate where the ASCIZ version of the ** first parameter should appear in the routine call. That token can appear ** any number of times. ** ** This macro only converts a single string. ** ** If the same ASCIZ string is going to be converted to PSE_STRING several ** times, you should make a 'permanent' PSE_STRING version of it using ** PSE_COPY_ASCIZ. */ #define pse_str_convert_asciz( asciz_string, parameter ) \ { \ pse_string _string; \ _string = pse_g_str_dynamic; \ pse_str_copy_asciz( &_string, asciz_string ); \ parameter; \ pse_str_free( &_string ); \ } /* ** PSE_STR_APPEND - Appends the source string to end of the destination string. */ void pse_str_append( pse_string *dst_string, pse_string *src_string ); /* ** PSE_STR_APPEND_ASCIZ - Appends an ASCIZ string to the destination string. */ void pse_str_append_asciz( pse_string *dst_string, pse_str_asciz src_string ); /* ** PSE_STR_APPEND_F - Appends a formatted string to the destination string. ** ** This routine works the same as PSE_STR_COPY_F, except that it appends ** rather than copies. */ void pse_str_append_f( pse_string *dst_string, pse_str_asciz src_format, ... ); /* ** PSE_STR_COMPARE - Compares to strings. ** ** This comparison is case-sensitive. ** ** Returns: ** -1 string1 is less than string2 ** 0 string1 is equal to string2 ** 1 string1 is greater than string2 */ unsigned int pse_str_compare( pse_string *string1, pse_string *string2 ); /* ** PSE_STR_COMPARE_ASCIZ - Compares a string to an ASCIZ string. ** ** This comparison is case-sensitive. ** ** Returns: ** -1 string1 is less than string2 ** 0 string1 is equal to string2 ** 1 string1 is greater than string2 */ unsigned int pse_str_compare_asciz( pse_string *string1, pse_str_asciz string2 ); /* ** PSE_STR_COMPARE_INSENSITIVE - Compares two strings. ** ** This comparison is case-insensitive. ** ** Returns: ** -1 string1 is less than string2 ** 0 string1 is equal to string2 ** 1 string1 is greater than string2 */ /* ** PSE_STR_COPY - Copies the source string to the destination string. */ void pse_str_copy( pse_string *dst_string, pse_string *src_string ); /* ** PSE_STR_COPY_ASCIZ - Copies an ASCIZ string to the destination string. */ void pse_str_copy_asciz( pse_string *dst_string, pse_str_asciz src_string ); /* ** PSE_STR_COPY_F - Copiss a formatted string to the destination string. ** ** This routine works the same as SPRINTF, except for the type of the ** destination string. */ void pse_str_copy_f( pse_string *dst_string, pse_str_asciz src_format, ... ); /* ** PSE_STR_COPY_RAW - Copies a string expressed in its most 'raw' form: ** a length and an address. */ void pse_str_copy_raw( pse_string *dst_string, pse_str_length src_length, pse_str_pointer src_pointer ); /* ** PSE_STR_COPY_TO_ASCIZ - Copies a source string to an ASCIZ buffer. ** ** This routine allocates memory for the ASCIZ string. The first time you ** pass a particular ASCIZ string (pointer) to this routine that pointer must ** contain zero (null). You can pass that ASCIZ string (pointer) to this ** routine any number of times -- this routine will automatically free and ** allocate memory as needed. When you are done with this ASCIZ string you ** must free it by calling PSE_STR_FREE_ASCIZ. */ void pse_str_copy_to_asciz( pse_str_asciz *dst_string, pse_string *src_string ); /* ** PSE_STR_DESCRIBE - Sets an initialized fixed string to point at a string. ** ** This routine does not make a copy of the string. */ void pse_str_describe( pse_string *dst_string, pse_string *src_string ); /* ** PSE_STR_DESCRIBE_ASCIZ - Sets an initialized fixed string to point at an ** ASCIZ string. ** ** This routine does not make a copy of the string. */ void pse_str_describe_asciz( pse_string *dst_string, pse_str_asciz src_string ); /* ** PSE_STR_DESCRIBE_RAW - Sets an initialized fixed string to point at a ** string expressed in its most 'raw' form: ** a length and an address. ** ** This routine does not make a copy of the string. */ void pse_str_describe_raw( pse_string *dst_string, pse_str_length src_length, pse_str_pointer src_pointer ); /* ** PSE_STR_DOWNCASE - Converts a string to lower case. */ void pse_str_downcase( pse_string *dst_string, pse_string *src_string ); /* ** PSE_STR_EQUAL - Test for string equality. ** ** This comparison is case-sensitive. ** ** Returns: ** 0 strings are different ** 1 strings are equal */ unsigned int pse_str_equal( pse_string *string1, pse_string *string2 ); /* ** PSE_STR_EQUAL_ASCIZ - Test for equality, given a PSE and an ASCIZ string. ** ** This comparison is case-sensitive. ** ** Returns: ** 0 strings are different ** 1 strings are equal */ unsigned int pse_str_equal_asciz( pse_string *string1, pse_str_asciz string2 ); /* ** PSE_STR_EQUAL_INSENSITIVE - Case-insensitive test for equality. ** ** This comparison is case-insensitive. ** ** Returns: ** -1 string1 is less than string2 ** 0 string1 is equal to string2 ** 1 string1 is greater than string2 */ unsigned int pse_str_equal_insensitive( pse_string *string1, pse_string *string2 ); /* ** PSE_STR_FREE - Frees a dynamic string. */ void pse_str_free( pse_string *string ); /* ** PSE_STR_FREE_ASCIZ - Frees an ASCIZ string buffer. ** ** This routine should be used to free memory allocated by ** PSE_STR_COPY_TO_ASCIZ. */ void pse_str_free_asciz( pse_str_asciz *string ); /* ** PSE_STR_GET_ASCIZ - Returns a pointer to a null-terminated string. ** ** This routine must be used carefully. The pointer returned is only valid ** as long as the string used to generate it is unchanged. If there is any ** question about its validity, use PSE_STR_COPY_TO_ASCIZ instead. ** ** This routine does not work for PSE_STR_FIXED strings. */ pse_str_asciz pse_str_get_asciz( pse_string *string ); #define asciz pse_str_get_asciz /* ** PSE_STR_GET_LENGTH - Returns the length of a string. */ pse_str_length pse_str_get_length( pse_string *string ); /* ** PSE_STR_GET_POINTER - Returns a pointer to a string. ** ** Note that this routine does not necessarily return a pointer to a ** null-terminated string. */ pse_str_pointer pse_str_get_pointer( pse_string *string ); /* ** PSE_STR_MOVE_TO_ASCIZ - Moves a source string to an existing ASCIZ buffer. ** ** This routine does not allocate memory. ** The ASCIZ buffer must be large enough to contain the string. */ void pse_str_move_to_asciz( pse_str_asciz dst_string, pse_str_length buffer_length, pse_string *src_string ); /* ** PSE_STR_UPCASE - Converts a string to upper case. */ void pse_str_upcase( pse_string *dst_string, pse_string *src_string ); /* ** PSE_STR_[@tbs@] - [@tbs@] [@tbs@] pse_str_[@tbs@]( pse_string *string[@tbs@] ); */ /* End of ignoring multiple includes in C programs. */ #endif /* pse_str__def */