OSDN Git Service

Replace INIT with DUMMY_INIT macro
[yash/yash.git] / util.h
1 /* Yash: yet another shell */
2 /* util.h: miscellaneous utility functions */
3 /* (C) 2007-2021 magicant */
4
5 /* This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18
19 #ifndef YASH_UTIL_H
20 #define YASH_UTIL_H
21
22 #include <stdlib.h>
23
24 #define Size_max ((size_t) -1)  // = SIZE_MAX
25
26
27 /********** Miscellaneous Functions **********/
28
29 static inline int xunsetenv(const char *name)
30     __attribute__((nonnull));
31
32 /* Removes the environment variable of the specified name.
33  * This function wraps the `unsetenv' function, which has an incompatible
34  * prototype on some old environments. */
35 int xunsetenv(const char *name)
36 {
37 #if UNSETENV_RETURNS_INT
38     return unsetenv(name);
39 #else
40     unsetenv(name);
41     return 0;
42 #endif
43 }
44
45
46 /********** Memory Functions **********/
47
48 static inline size_t add(size_t a, size_t b)
49     __attribute__((pure));
50 static inline size_t mul(size_t a, size_t b)
51     __attribute__((pure));
52
53 static inline void *xcalloc(size_t nmemb, size_t size)
54     __attribute__((malloc,warn_unused_result));
55 static inline void *xmalloc(size_t size)
56     __attribute__((malloc,warn_unused_result));
57 static inline void *xmallocn(size_t count, size_t elemsize)
58     __attribute__((malloc,warn_unused_result));
59 static inline void *xmalloce(size_t count1, size_t count2, size_t elemsize)
60     __attribute__((malloc,warn_unused_result));
61 static inline void *xmallocs(size_t mainsize, size_t count, size_t elemsize)
62     __attribute__((malloc,warn_unused_result));
63 static inline void *xrealloc(void *ptr, size_t size)
64     __attribute__((malloc,warn_unused_result));
65 static inline void *xreallocn(void *ptr, size_t count, size_t elemsize)
66     __attribute__((malloc,warn_unused_result));
67 static inline void *xrealloce(void *ptr,
68         size_t count1, size_t count2, size_t elemsize)
69     __attribute__((malloc,warn_unused_result));
70 static inline void *xreallocs(void *ptr,
71         size_t mainsize, size_t count, size_t elemsize)
72     __attribute__((malloc,warn_unused_result));
73 extern void alloc_failed(void)
74     __attribute__((noreturn));
75
76 /* Computes `a + b', but aborts the program by ENOMEM if the result overflows.
77  */
78 size_t add(size_t a, size_t b)
79 {
80     size_t sum = a + b;
81     if (sum < a)
82         alloc_failed();
83     return sum;
84 }
85
86 /* Computes `a * b', but aborts the program by ENOMEM if the result overflows.
87  */
88 size_t mul(size_t a, size_t b)
89 {
90     size_t product = a * b;
91     if (b != 0 && product / b != a)
92         alloc_failed();
93     return product;
94 }
95
96 /* Attempts `calloc' and aborts the program on failure. */
97 void *xcalloc(size_t nmemb, size_t size)
98 {
99     void *result = calloc(nmemb, size);
100     if (result == NULL && nmemb > 0 && size > 0)
101         alloc_failed();
102     return result;
103 }
104
105 /* Attempts `malloc' and aborts the program on failure. */
106 void *xmalloc(size_t size)
107 {
108     void *result = malloc(size);
109     if (result == NULL && size > 0)
110         alloc_failed();
111     return result;
112 }
113
114 /* Like `xmalloc(count * elemsize)', but aborts the program if the size is too
115  * large. */
116 void *xmallocn(size_t count, size_t elemsize)
117 {
118     return xmalloc(mul(count, elemsize));
119 }
120
121 /* Like `xmalloc((count1 + count2) * elemsize)', but aborts the program if the
122  * size is too large. */
123 void *xmalloce(size_t count1, size_t count2, size_t elemsize)
124 {
125     return xmallocn(add(count1, count2), elemsize);
126 }
127
128 /* Like `xmalloc(mainsize + count * elemsize)', but aborts the program if the
129  * size is too large. */
130 void *xmallocs(size_t mainsize, size_t count, size_t elemsize)
131 {
132     return xmalloc(add(mainsize, mul(count, elemsize)));
133 }
134
135 /* Attempts `realloc' and aborts the program on failure. */
136 void *xrealloc(void *ptr, size_t size)
137 {
138     /* The behavior of `realloc(non_null_pointer, 0)' is unreliable. Some
139      * implementations free the previously allocated region and return NULL.
140      * Some reallocate an empty region and return a pointer to it. The latter
141      * may fail to allocate the new region, leaving the previous region intact
142      * and returning NULL. That means, when `realloc(non_null_pointer, 0)'
143      * returned NULL, we cannot tell if the previous region has been freed or
144      * not. */
145     if (size == 0) {
146         free(ptr);
147         return NULL;
148     }
149
150     void *result = realloc(ptr, size);
151     if (result == NULL)
152         alloc_failed();
153     return result;
154 }
155
156 /* Like `xrealloc(ptr, count * elemsize)', but aborts the program if the size is
157  * too large. */
158 void *xreallocn(void *ptr, size_t count, size_t elemsize)
159 {
160     return xrealloc(ptr, mul(count, elemsize));
161 }
162
163 /* Like `xrealloc(ptr, (count1 + count2) * elemsize)', but aborts the program if
164  * the size is too large. */
165 void *xrealloce(void *ptr, size_t count1, size_t count2, size_t elemsize)
166 {
167     return xreallocn(ptr, add(count1, count2), elemsize);
168 }
169
170 /* Like `xrealloc(ptr, mainsize + count * elemsize)', but aborts the program if
171  * the size is too large. */
172 void *xreallocs(void *ptr, size_t mainsize, size_t count, size_t elemsize)
173 {
174     return xrealloc(ptr, add(mainsize, mul(count, elemsize)));
175 }
176
177
178 /********** String Utilities **********/
179
180 #if !HAVE_STRNLEN
181 extern size_t xstrnlen(const char *s, size_t maxlen)
182     __attribute__((pure,nonnull));
183 #endif
184 #if !HAVE_STRDUP
185 extern char *xstrdup(const char *s)
186     __attribute__((malloc,warn_unused_result,nonnull));
187 #endif
188 #if !HAVE_WCSNLEN
189 extern size_t xwcsnlen(const wchar_t *s, size_t maxlen)
190     __attribute__((pure,nonnull));
191 #endif
192 extern wchar_t *xwcsndup(const wchar_t *s, size_t maxlen)
193     __attribute__((malloc,warn_unused_result,nonnull));
194 #if !HAVE_WCSDUP
195 static inline wchar_t *xwcsdup(const wchar_t *s)
196     __attribute__((malloc,warn_unused_result,nonnull));
197 #endif
198 extern _Bool xstrtoi(const char *s, int base, int *resultp)
199     __attribute__((warn_unused_result,nonnull));
200 extern _Bool xwcstoi(const wchar_t *s, int base, int *resultp)
201     __attribute__((warn_unused_result,nonnull));
202 extern _Bool xwcstol(const wchar_t *s, int base, long *resultp)
203     __attribute__((warn_unused_result,nonnull));
204 extern _Bool xwcstoul(const wchar_t *s, int base, unsigned long *resultp)
205     __attribute__((warn_unused_result,nonnull));
206 extern char *matchstrprefix(const char *s, const char *prefix)
207     __attribute__((pure,nonnull));
208 extern wchar_t *matchwcsprefix(const wchar_t *s, const wchar_t *prefix)
209     __attribute__((pure,nonnull));
210 extern void *copyaswcs(const void *p)
211     __attribute__((malloc,warn_unused_result,nonnull));
212
213 #if HAVE_STRNLEN
214 # ifndef strnlen
215 extern size_t strnlen(const char *s, size_t maxlen);
216 # endif
217 # define xstrnlen strnlen
218 #endif
219
220 #if HAVE_STRDUP
221 # ifndef strdup
222 extern char *strdup(const char *s);
223 # endif
224 # define xstrdup strdup
225 #endif
226
227 #if HAVE_WCSNLEN
228 # ifndef wcsnlen
229 extern size_t wcsnlen(const wchar_t *s, size_t maxlen);
230 # endif
231 # define xwcsnlen wcsnlen
232 #endif
233
234 #if HAVE_WCSDUP
235 # ifndef wcsdup
236 extern wchar_t *wcsdup(const wchar_t *s);
237 # endif
238 # define xwcsdup wcsdup
239 #else
240 /* Returns a newly malloced copy of the specified string.
241  * Aborts the program if failed to allocate memory. */
242 wchar_t *xwcsdup(const wchar_t *s)
243 {
244     return xwcsndup(s, Size_max);
245 }
246 #endif
247
248
249 /* These macros are used to cast the argument properly.
250  * We don't need such macros for wide characters. */
251 #define xisalnum(c)  (isalnum((unsigned char) (c)))
252 #define xisalpha(c)  (isalpha((unsigned char) (c)))
253 #define xisblank(c)  (isblank((unsigned char) (c)))
254 #define xiscntrl(c)  (iscntrl((unsigned char) (c)))
255 #define xisdigit(c)  (isdigit((unsigned char) (c)))
256 #define xisgraph(c)  (isgraph((unsigned char) (c)))
257 #define xislower(c)  (islower((unsigned char) (c)))
258 #define xisprint(c)  (isprint((unsigned char) (c)))
259 #define xispunct(c)  (ispunct((unsigned char) (c)))
260 #define xisspace(c)  (isspace((unsigned char) (c)))
261 #define xisupper(c)  (isupper((unsigned char) (c)))
262 #define xisxdigit(c) (isxdigit((unsigned char) (c)))
263 #define xtoupper(c)  (toupper((unsigned char) (c)))
264 #define xtolower(c)  (tolower((unsigned char) (c)))
265
266
267 /* Casts scalar to char safely. */
268 #define TO_CHAR(value) \
269     ((union { char c; unsigned char uc; }) { .uc = (unsigned char) (value), }.c)
270
271
272 /********** Error Utilities **********/
273
274 extern const wchar_t *yash_program_invocation_name;
275 extern const wchar_t *yash_program_invocation_short_name;
276 extern const wchar_t *current_builtin_name;
277 extern unsigned yash_error_message_count;
278 extern void xerror(int errno_, const char *restrict format, ...)
279     __attribute__((format(printf,2,3)));
280
281 extern _Bool xprintf(const char *restrict format, ...)
282     __attribute__((format(printf,1,2)));
283
284
285 #undef Size_max
286
287 #endif /* YASH_UTIL_H */
288
289
290 /* vim: set ts=8 sts=4 sw=4 et tw=80: */