1 #ifndef _NSTRING_H
2 #define _NSTRING_H
3 
4 #include <stdarg.h>
5 #include <string.h>
6 #include <strings.h>  /* For strncasecmp */
7 #include <ctype.h>
8 
9 #include "pm_c_util.h"
10 #include "pm.h"  /* For PM_GNU_PRINTF_ATTR, __inline__ */
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 #if 0
16 } /* to fake out automatic code indenters */
17 #endif
18 
19 /* Here are string functions that respect the size of the array
20    into which you are copying -- E.g. STRSCPY truncates the source string as
21    required so that it fits, with the terminating null, in the destination
22    array.
23 */
24 #define STRSCPY(A,B) \
25 	(strncpy((A), (B), sizeof(A)), *((A)+sizeof(A)-1) = '\0')
26 #define STRSCMP(A,B) \
27 	(strncmp((A), (B), sizeof(A)))
28 #define STRSCAT(A,B) \
29     (strncpy(A+strlen(A), B, sizeof(A)-strlen(A)), *((A)+sizeof(A)-1) = '\0')
30 #define STRSEQ(A, B) \
31 	(strneq((A), (B), sizeof(A)))
32 
33 #define MEMEQ(a,b,c) (memcmp(a, b, c) == 0)
34 
35 #define MEMSEQ(a,b) (memeq(a, b, sizeof(*(a))) == 0)
36 
37 #define MEMSSET(a,b) (memset(a, b, sizeof(*(a))))
38 
39 #define MEMSCPY(a,b) (memcpy(a, b, sizeof(*(a))))
40 
41 #define MEMSZERO(a) (MEMSSET(a, 0))
42 
43 
44 static __inline__ int
streq(const char * const comparand,const char * const comparator)45 streq(const char * const comparand,
46       const char * const comparator) {
47 
48     return strcmp(comparand, comparator) == 0;
49 }
50 
51 static __inline__ int
strneq(const char * const comparand,const char * const comparator,size_t const size)52 strneq(const char * const comparand,
53        const char * const comparator,
54        size_t       const size) {
55 
56     return strncmp(comparand, comparator, size) == 0;
57 }
58 
59 static __inline__ int
memeq(const void * const comparand,const void * const comparator,size_t const size)60 memeq(const void * const comparand,
61       const void * const comparator,
62       size_t       const size) {
63 
64     return memcmp(comparand, comparator, size) == 0;
65 }
66 
67 /* The Standard C Library may not declare strcasecmp() if the including source
68    file doesn't request BSD functions, with _BSD_SOURCE or SUSv2 function,
69    with _XOPEN_SOURCE >= 500.  So we don't define functions that use
70    strcasecmp() in that case.
71 
72    (Actually, _XOPEN_SOURCE 500 is stronger than you need for strcasecmp -
73    _XOPEN_SOURCE_EXTENDED, which asks for XPG 4, would do, whereas
74    _XOPEN_SOURCE 500 asks for XPG 5, but for simplicity, we don't use
75    _XOPEN_SOURCE_EXTENDED in Netpbm.
76 */
77 #if defined(_BSD_SOURCE) || (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE - 0) >= 500)
78 static __inline__ int
strcaseeq(const char * const comparand,const char * const comparator)79 strcaseeq(const char * const comparand,
80           const char * const comparator) {
81 
82     return strcasecmp(comparand, comparator) == 0;
83 }
84 
85 static __inline__ int
strncaseeq(const char * const comparand,const char * const comparator,size_t const size)86 strncaseeq(const char * const comparand,
87            const char * const comparator,
88            size_t       const size) {
89 
90     return strncasecmp(comparand, comparator, size) == 0;
91 }
92 #endif
93 
94 
95 /* The standard C library routines isdigit(), for some weird
96    historical reason, does not take a character (type 'char') as its
97    argument.  Instead it takes an integer.  When the integer is a whole
98    number, it represents a character in the obvious way using the local
99    character set encoding.  When the integer is negative, the results
100    are undefined.
101 
102    Passing a character to isdigit(), which expects an integer, results in
103    isdigit() sometimes getting a negative number.
104 
105    On some systems, when the integer is negative, it represents exactly
106    the character you want it to anyway (e.g. -1 is the character that is
107    encoded 0xFF).  But on others, it does not.
108 
109    (The same is true of other routines like isdigit()).
110 
111    Therefore, we have the substitutes for isdigit() etc. that take an
112    actual character (type 'char') as an argument.
113 */
114 
115 #define ISALNUM(C) (isalnum((unsigned char)(C)))
116 #define ISALPHA(C) (isalpha((unsigned char)(C)))
117 #define ISCNTRL(C) (iscntrl((unsigned char)(C)))
118 #define ISDIGIT(C) (isdigit((unsigned char)(C)))
119 #define ISGRAPH(C) (isgraph((unsigned char)(C)))
120 #define ISLOWER(C) (islower((unsigned char)(C)))
121 #define ISPRINT(C) (isprint((unsigned char)(C)))
122 #define ISPUNCT(C) (ispunct((unsigned char)(C)))
123 #define ISSPACE(C) (isspace((unsigned char)(C)))
124 #define ISUPPER(C) (isupper((unsigned char)(C)))
125 #define ISXDIGIT(C) (isxdigit((unsigned char)(C)))
126 #define TOUPPER(C) ((char)toupper((unsigned char)(C)))
127 
128 
129 /* These are all private versions of commonly available standard C
130    library subroutines whose names are the same except with the N at
131    the end.  Because not all standard C libraries have them all,
132    Netpbm must include them in its own libraries, and because some
133    standard C libraries have some of them, Netpbm must use different
134    names for them.
135 
136    The GNU C library has all of them.  All but the oldest standard C libraries
137    have snprintf().
138 
139    There are slight differences between the asprintf() family and that
140    found in other libraries:
141 
142      - There is no return value.
143 
144      - The returned string is a const char * instead of a char *.  The
145        const is more correct.
146 
147      - If the function can't get the memory, it returns 'pm_strsol',
148        which is a string that is in static memory that contains text
149        indicating an out of memory failure has occurred, instead of
150        NULL.  This makes it much easier for programs to ignore this
151        possibility.
152 
153    strfree() is strictly a Netpbm invention, to allow proper type checking
154    when freeing storage allocated by the Netpbm pm_asprintf().
155 */
156 
157 extern const char * const pm_strsol;
158 
159 size_t
160 pm_strnlen(const char * const s,
161            size_t       const maxlen);
162 
163 int
164 pm_snprintf(char *       const dest,
165             size_t       const str_m,
166             const char * const fmt,
167             ...) PM_GNU_PRINTF_ATTR(3,4);
168 
169 void
170 pm_vsnprintf(char *       const str,
171              size_t       const str_m,
172              const char * const fmt,
173              va_list            ap,
174              size_t *     const sizeP);
175 
176 const char *
177 pm_strdup(const char * const arg);
178 
179 void
180 pm_asprintf(const char ** const resultP,
181             const char *  const fmt,
182             ...) PM_GNU_PRINTF_ATTR(2,3);
183 
184 void
185 pm_vasprintf(const char ** const resultP,
186              const char *  const format,
187              va_list             args);
188 
189 bool
190 pm_vasprintf_knows_float(void);
191 
192 void
193 pm_strfree(const char * const string);
194 
195 const char *
196 pm_strsep(char ** const stringP, const char * const delim);
197 
198 int
199 pm_stripeq(const char * const comparand,
200            const char * const comparator);
201 
202 const void *
203 pm_memmem(const void * const haystackArg,
204           size_t       const haystacklen,
205           const void * const needleArg,
206           size_t       const needlelen);
207 
208 bool
209 pm_strishex(const char * const subject);
210 
211 void
212 pm_string_to_long(const char *   const string,
213                   long *         const longP,
214                   const char **  const errorP);
215 
216 void
217 pm_string_to_int(const char *   const string,
218                  int *          const intP,
219                  const char **  const errorP);
220 
221 void
222 pm_string_to_uint(const char *   const string,
223                   unsigned int * const uintP,
224                   const char **  const errorP);
225 
226 #ifdef __cplusplus
227 }
228 #endif
229 
230 #endif
231