diff options
author | Ton Voon <tonvoon@users.sourceforge.net> | 2007-01-24 22:47:25 +0000 |
---|---|---|
committer | Ton Voon <tonvoon@users.sourceforge.net> | 2007-01-24 22:47:25 +0000 |
commit | fe856aa957978504137c1d425815d4ed8a22be40 (patch) | |
tree | a5bb46ce0e64b2056f75700eadbf27aba7c39418 /gl | |
parent | 210f39bc84cfbb21cd72dc054e43f13815ee0616 (diff) | |
download | monitoring-plugins-fe856aa957978504137c1d425815d4ed8a22be40.tar.gz |
Sync with gnulib - lots of extraneous code removed in preference to GNU code
git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@1580 f882894a-f735-0410-b71e-b25c423dba1c
Diffstat (limited to 'gl')
190 files changed, 31850 insertions, 0 deletions
diff --git a/gl/Makefile.am b/gl/Makefile.am new file mode 100644 index 00000000..67c9872d --- /dev/null +++ b/gl/Makefile.am | |||
@@ -0,0 +1,607 @@ | |||
1 | ## DO NOT EDIT! GENERATED AUTOMATICALLY! | ||
2 | ## Process this file with automake to produce Makefile.in. | ||
3 | # Copyright (C) 2004-2007 Free Software Foundation, Inc. | ||
4 | # | ||
5 | # This file is free software, distributed under the terms of the GNU | ||
6 | # General Public License. As a special exception to the GNU General | ||
7 | # Public License, this file may be distributed as part of a program | ||
8 | # that contains a configuration script generated by Autoconf, under | ||
9 | # the same distribution terms as the rest of that program. | ||
10 | # | ||
11 | # Generated by gnulib-tool. | ||
12 | # Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --aux-dir=. --no-libtool --macro-prefix=gl dirname fsusage getaddrinfo gethostname getloadavg getopt gettext mountlist regex vasprintf vsnprintf | ||
13 | |||
14 | AUTOMAKE_OPTIONS = 1.5 gnits | ||
15 | |||
16 | noinst_HEADERS = | ||
17 | noinst_LIBRARIES = | ||
18 | noinst_LTLIBRARIES = | ||
19 | EXTRA_DIST = | ||
20 | BUILT_SOURCES = | ||
21 | SUFFIXES = | ||
22 | MOSTLYCLEANFILES = core *.stackdump | ||
23 | MOSTLYCLEANDIRS = | ||
24 | CLEANFILES = | ||
25 | DISTCLEANFILES = | ||
26 | MAINTAINERCLEANFILES = | ||
27 | |||
28 | AM_CPPFLAGS = | ||
29 | |||
30 | noinst_LIBRARIES += libgnu.a | ||
31 | |||
32 | libgnu_a_SOURCES = | ||
33 | libgnu_a_LIBADD = $(gl_LIBOBJS) | ||
34 | libgnu_a_DEPENDENCIES = $(gl_LIBOBJS) | ||
35 | EXTRA_libgnu_a_SOURCES = | ||
36 | |||
37 | ## begin gnulib module alloca | ||
38 | |||
39 | |||
40 | EXTRA_DIST += alloca.c | ||
41 | |||
42 | EXTRA_libgnu_a_SOURCES += alloca.c | ||
43 | |||
44 | libgnu_a_LIBADD += @ALLOCA@ | ||
45 | libgnu_a_DEPENDENCIES += @ALLOCA@ | ||
46 | ## end gnulib module alloca | ||
47 | |||
48 | ## begin gnulib module alloca-opt | ||
49 | |||
50 | BUILT_SOURCES += $(ALLOCA_H) | ||
51 | |||
52 | # We need the following in order to create <alloca.h> when the system | ||
53 | # doesn't have one that works with the given compiler. | ||
54 | alloca.h: alloca_.h | ||
55 | { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ | ||
56 | cat $(srcdir)/alloca_.h; \ | ||
57 | } > $@-t | ||
58 | mv -f $@-t $@ | ||
59 | MOSTLYCLEANFILES += alloca.h alloca.h-t | ||
60 | |||
61 | EXTRA_DIST += alloca_.h | ||
62 | |||
63 | ## end gnulib module alloca-opt | ||
64 | |||
65 | ## begin gnulib module arpa_inet | ||
66 | |||
67 | BUILT_SOURCES += $(ARPA_INET_H) | ||
68 | |||
69 | # We need the following in order to create <arpa/inet.h> when the system | ||
70 | # doesn't have one. | ||
71 | arpa/inet.h: | ||
72 | test -d arpa || mkdir arpa | ||
73 | rm -f $@-t $@ | ||
74 | { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ | ||
75 | echo '#include <sys/socket.h>'; \ | ||
76 | } > $@-t | ||
77 | mv $@-t $@ | ||
78 | MOSTLYCLEANFILES += arpa/inet.h arpa/inet.h-t | ||
79 | MOSTLYCLEANDIRS += arpa | ||
80 | |||
81 | ## end gnulib module arpa_inet | ||
82 | |||
83 | ## begin gnulib module c-strtod | ||
84 | |||
85 | |||
86 | EXTRA_DIST += c-strtod.c c-strtod.h | ||
87 | |||
88 | EXTRA_libgnu_a_SOURCES += c-strtod.c | ||
89 | |||
90 | ## end gnulib module c-strtod | ||
91 | |||
92 | ## begin gnulib module cloexec | ||
93 | |||
94 | |||
95 | EXTRA_DIST += cloexec.c cloexec.h | ||
96 | |||
97 | EXTRA_libgnu_a_SOURCES += cloexec.c | ||
98 | |||
99 | ## end gnulib module cloexec | ||
100 | |||
101 | ## begin gnulib module dirname | ||
102 | |||
103 | |||
104 | EXTRA_DIST += basename.c dirname.c dirname.h stripslash.c | ||
105 | |||
106 | EXTRA_libgnu_a_SOURCES += basename.c dirname.c stripslash.c | ||
107 | |||
108 | ## end gnulib module dirname | ||
109 | |||
110 | ## begin gnulib module error | ||
111 | |||
112 | |||
113 | EXTRA_DIST += error.c error.h | ||
114 | |||
115 | EXTRA_libgnu_a_SOURCES += error.c | ||
116 | |||
117 | ## end gnulib module error | ||
118 | |||
119 | ## begin gnulib module exit | ||
120 | |||
121 | libgnu_a_SOURCES += exit.h | ||
122 | |||
123 | ## end gnulib module exit | ||
124 | |||
125 | ## begin gnulib module exitfail | ||
126 | |||
127 | |||
128 | EXTRA_DIST += exitfail.c exitfail.h | ||
129 | |||
130 | EXTRA_libgnu_a_SOURCES += exitfail.c | ||
131 | |||
132 | ## end gnulib module exitfail | ||
133 | |||
134 | ## begin gnulib module fcntl-safer | ||
135 | |||
136 | |||
137 | EXTRA_DIST += creat-safer.c fcntl--.h fcntl-safer.h open-safer.c | ||
138 | |||
139 | EXTRA_libgnu_a_SOURCES += creat-safer.c open-safer.c | ||
140 | |||
141 | ## end gnulib module fcntl-safer | ||
142 | |||
143 | ## begin gnulib module fsusage | ||
144 | |||
145 | |||
146 | EXTRA_DIST += fsusage.c fsusage.h | ||
147 | |||
148 | EXTRA_libgnu_a_SOURCES += fsusage.c | ||
149 | |||
150 | ## end gnulib module fsusage | ||
151 | |||
152 | ## begin gnulib module full-read | ||
153 | |||
154 | libgnu_a_SOURCES += full-read.h full-read.c | ||
155 | |||
156 | ## end gnulib module full-read | ||
157 | |||
158 | ## begin gnulib module full-write | ||
159 | |||
160 | libgnu_a_SOURCES += full-write.h full-write.c | ||
161 | |||
162 | ## end gnulib module full-write | ||
163 | |||
164 | ## begin gnulib module getaddrinfo | ||
165 | |||
166 | |||
167 | EXTRA_DIST += gai_strerror.c getaddrinfo.c getaddrinfo.h | ||
168 | |||
169 | EXTRA_libgnu_a_SOURCES += gai_strerror.c getaddrinfo.c | ||
170 | |||
171 | ## end gnulib module getaddrinfo | ||
172 | |||
173 | ## begin gnulib module gethostname | ||
174 | |||
175 | |||
176 | EXTRA_DIST += gethostname.c | ||
177 | |||
178 | EXTRA_libgnu_a_SOURCES += gethostname.c | ||
179 | |||
180 | ## end gnulib module gethostname | ||
181 | |||
182 | ## begin gnulib module getloadavg | ||
183 | |||
184 | |||
185 | EXTRA_DIST += getloadavg.c | ||
186 | |||
187 | EXTRA_libgnu_a_SOURCES += getloadavg.c | ||
188 | |||
189 | ## end gnulib module getloadavg | ||
190 | |||
191 | ## begin gnulib module getopt | ||
192 | |||
193 | BUILT_SOURCES += $(GETOPT_H) | ||
194 | |||
195 | # We need the following in order to create <getopt.h> when the system | ||
196 | # doesn't have one that works with the given compiler. | ||
197 | getopt.h: getopt_.h | ||
198 | { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ | ||
199 | cat $(srcdir)/getopt_.h; \ | ||
200 | } > $@-t | ||
201 | mv -f $@-t $@ | ||
202 | MOSTLYCLEANFILES += getopt.h getopt.h-t | ||
203 | |||
204 | EXTRA_DIST += getopt.c getopt1.c getopt_.h getopt_int.h | ||
205 | |||
206 | EXTRA_libgnu_a_SOURCES += getopt.c getopt1.c | ||
207 | |||
208 | ## end gnulib module getopt | ||
209 | |||
210 | ## begin gnulib module gettext | ||
211 | |||
212 | # This is for those projects which use "gettextize --intl" to put a source-code | ||
213 | # copy of libintl into their package. In such projects, every Makefile.am needs | ||
214 | # -I$(top_builddir)/intl, so that <libintl.h> can be found in this directory. | ||
215 | # For the Makefile.ams in other directories it is the maintainer's | ||
216 | # responsibility; for the one from gnulib we do it here. | ||
217 | # This option has no effect when the user disables NLS (because then the intl | ||
218 | # directory contains no libintl.h file) or when the project does not use | ||
219 | # "gettextize --intl". | ||
220 | AM_CPPFLAGS += -I$(top_builddir)/intl | ||
221 | |||
222 | ## end gnulib module gettext | ||
223 | |||
224 | ## begin gnulib module gettext-h | ||
225 | |||
226 | libgnu_a_SOURCES += gettext.h | ||
227 | |||
228 | ## end gnulib module gettext-h | ||
229 | |||
230 | ## begin gnulib module inet_ntop | ||
231 | |||
232 | |||
233 | EXTRA_DIST += inet_ntop.c inet_ntop.h | ||
234 | |||
235 | EXTRA_libgnu_a_SOURCES += inet_ntop.c | ||
236 | |||
237 | ## end gnulib module inet_ntop | ||
238 | |||
239 | ## begin gnulib module intprops | ||
240 | |||
241 | |||
242 | EXTRA_DIST += intprops.h | ||
243 | |||
244 | ## end gnulib module intprops | ||
245 | |||
246 | ## begin gnulib module malloc | ||
247 | |||
248 | |||
249 | EXTRA_DIST += malloc.c | ||
250 | |||
251 | EXTRA_libgnu_a_SOURCES += malloc.c | ||
252 | |||
253 | ## end gnulib module malloc | ||
254 | |||
255 | ## begin gnulib module mbchar | ||
256 | |||
257 | |||
258 | EXTRA_DIST += mbchar.c mbchar.h | ||
259 | |||
260 | EXTRA_libgnu_a_SOURCES += mbchar.c | ||
261 | |||
262 | ## end gnulib module mbchar | ||
263 | |||
264 | ## begin gnulib module mbuiter | ||
265 | |||
266 | libgnu_a_SOURCES += mbuiter.h | ||
267 | |||
268 | ## end gnulib module mbuiter | ||
269 | |||
270 | ## begin gnulib module memchr | ||
271 | |||
272 | |||
273 | EXTRA_DIST += memchr.c | ||
274 | |||
275 | EXTRA_libgnu_a_SOURCES += memchr.c | ||
276 | |||
277 | ## end gnulib module memchr | ||
278 | |||
279 | ## begin gnulib module minmax | ||
280 | |||
281 | libgnu_a_SOURCES += minmax.h | ||
282 | |||
283 | ## end gnulib module minmax | ||
284 | |||
285 | ## begin gnulib module mountlist | ||
286 | |||
287 | |||
288 | EXTRA_DIST += mountlist.c mountlist.h | ||
289 | |||
290 | EXTRA_libgnu_a_SOURCES += mountlist.c | ||
291 | |||
292 | ## end gnulib module mountlist | ||
293 | |||
294 | ## begin gnulib module netinet_in | ||
295 | |||
296 | BUILT_SOURCES += $(NETINET_IN_H) | ||
297 | |||
298 | # We need the following in order to create <netinet/in.h> when the system | ||
299 | # doesn't have one. | ||
300 | netinet/in.h: | ||
301 | test -d netinet || mkdir netinet | ||
302 | rm -f $@-t $@ | ||
303 | { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ | ||
304 | echo '#include <sys/socket.h>'; \ | ||
305 | } > $@-t | ||
306 | mv $@-t $@ | ||
307 | MOSTLYCLEANFILES += netinet/in.h netinet/in.h-t | ||
308 | MOSTLYCLEANDIRS += netinet | ||
309 | |||
310 | ## end gnulib module netinet_in | ||
311 | |||
312 | ## begin gnulib module regex | ||
313 | |||
314 | |||
315 | EXTRA_DIST += regcomp.c regex.c regex.h regex_internal.c regex_internal.h regexec.c | ||
316 | |||
317 | EXTRA_libgnu_a_SOURCES += regcomp.c regex.c regex_internal.c regexec.c | ||
318 | |||
319 | ## end gnulib module regex | ||
320 | |||
321 | ## begin gnulib module safe-read | ||
322 | |||
323 | |||
324 | EXTRA_DIST += safe-read.c safe-read.h | ||
325 | |||
326 | EXTRA_libgnu_a_SOURCES += safe-read.c | ||
327 | |||
328 | ## end gnulib module safe-read | ||
329 | |||
330 | ## begin gnulib module safe-write | ||
331 | |||
332 | |||
333 | EXTRA_DIST += safe-write.c safe-write.h | ||
334 | |||
335 | EXTRA_libgnu_a_SOURCES += safe-write.c | ||
336 | |||
337 | ## end gnulib module safe-write | ||
338 | |||
339 | ## begin gnulib module size_max | ||
340 | |||
341 | libgnu_a_SOURCES += size_max.h | ||
342 | |||
343 | ## end gnulib module size_max | ||
344 | |||
345 | ## begin gnulib module snprintf | ||
346 | |||
347 | |||
348 | EXTRA_DIST += snprintf.c snprintf.h | ||
349 | |||
350 | EXTRA_libgnu_a_SOURCES += snprintf.c | ||
351 | |||
352 | ## end gnulib module snprintf | ||
353 | |||
354 | ## begin gnulib module stdbool | ||
355 | |||
356 | BUILT_SOURCES += $(STDBOOL_H) | ||
357 | |||
358 | # We need the following in order to create <stdbool.h> when the system | ||
359 | # doesn't have one that works. | ||
360 | stdbool.h: stdbool_.h | ||
361 | rm -f $@-t $@ | ||
362 | { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ | ||
363 | sed -e 's/@''HAVE__BOOL''@/$(HAVE__BOOL)/g' < $(srcdir)/stdbool_.h; \ | ||
364 | } > $@-t | ||
365 | mv $@-t $@ | ||
366 | MOSTLYCLEANFILES += stdbool.h stdbool.h-t | ||
367 | |||
368 | EXTRA_DIST += stdbool_.h | ||
369 | |||
370 | ## end gnulib module stdbool | ||
371 | |||
372 | ## begin gnulib module stdint | ||
373 | |||
374 | BUILT_SOURCES += $(STDINT_H) | ||
375 | |||
376 | # We need the following in order to create <stdint.h> when the system | ||
377 | # doesn't have one that works with the given compiler. | ||
378 | stdint.h: stdint_.h | ||
379 | rm -f $@-t $@ | ||
380 | { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ | ||
381 | sed -e 's/@''HAVE_STDINT_H''@/$(HAVE_STDINT_H)/g' \ | ||
382 | -e 's|@''ABSOLUTE_STDINT_H''@|$(ABSOLUTE_STDINT_H)|g' \ | ||
383 | -e 's/@''HAVE_SYS_TYPES_H''@/$(HAVE_SYS_TYPES_H)/g' \ | ||
384 | -e 's/@''HAVE_INTTYPES_H''@/$(HAVE_INTTYPES_H)/g' \ | ||
385 | -e 's/@''HAVE_SYS_INTTYPES_H''@/$(HAVE_SYS_INTTYPES_H)/g' \ | ||
386 | -e 's/@''HAVE_SYS_BITYPES_H''@/$(HAVE_SYS_BITYPES_H)/g' \ | ||
387 | -e 's/@''HAVE_LONG_LONG_INT''@/$(HAVE_LONG_LONG_INT)/g' \ | ||
388 | -e 's/@''HAVE_UNSIGNED_LONG_LONG_INT''@/$(HAVE_UNSIGNED_LONG_LONG_INT)/g' \ | ||
389 | -e 's/@''BITSIZEOF_PTRDIFF_T''@/$(BITSIZEOF_PTRDIFF_T)/g' \ | ||
390 | -e 's/@''PTRDIFF_T_SUFFIX''@/$(PTRDIFF_T_SUFFIX)/g' \ | ||
391 | -e 's/@''BITSIZEOF_SIG_ATOMIC_T''@/$(BITSIZEOF_SIG_ATOMIC_T)/g' \ | ||
392 | -e 's/@''HAVE_SIGNED_SIG_ATOMIC_T''@/$(HAVE_SIGNED_SIG_ATOMIC_T)/g' \ | ||
393 | -e 's/@''SIG_ATOMIC_T_SUFFIX''@/$(SIG_ATOMIC_T_SUFFIX)/g' \ | ||
394 | -e 's/@''BITSIZEOF_SIZE_T''@/$(BITSIZEOF_SIZE_T)/g' \ | ||
395 | -e 's/@''SIZE_T_SUFFIX''@/$(SIZE_T_SUFFIX)/g' \ | ||
396 | -e 's/@''BITSIZEOF_WCHAR_T''@/$(BITSIZEOF_WCHAR_T)/g' \ | ||
397 | -e 's/@''HAVE_SIGNED_WCHAR_T''@/$(HAVE_SIGNED_WCHAR_T)/g' \ | ||
398 | -e 's/@''WCHAR_T_SUFFIX''@/$(WCHAR_T_SUFFIX)/g' \ | ||
399 | -e 's/@''BITSIZEOF_WINT_T''@/$(BITSIZEOF_WINT_T)/g' \ | ||
400 | -e 's/@''HAVE_SIGNED_WINT_T''@/$(HAVE_SIGNED_WINT_T)/g' \ | ||
401 | -e 's/@''WINT_T_SUFFIX''@/$(WINT_T_SUFFIX)/g' \ | ||
402 | < $(srcdir)/stdint_.h; \ | ||
403 | } > $@-t | ||
404 | mv $@-t $@ | ||
405 | MOSTLYCLEANFILES += stdint.h stdint.h-t | ||
406 | |||
407 | EXTRA_DIST += stdint_.h | ||
408 | |||
409 | ## end gnulib module stdint | ||
410 | |||
411 | ## begin gnulib module strcase | ||
412 | |||
413 | |||
414 | EXTRA_DIST += strcase.h strcasecmp.c strncasecmp.c | ||
415 | |||
416 | EXTRA_libgnu_a_SOURCES += strcasecmp.c strncasecmp.c | ||
417 | |||
418 | ## end gnulib module strcase | ||
419 | |||
420 | ## begin gnulib module strdup | ||
421 | |||
422 | |||
423 | EXTRA_DIST += strdup.c strdup.h | ||
424 | |||
425 | EXTRA_libgnu_a_SOURCES += strdup.c | ||
426 | |||
427 | ## end gnulib module strdup | ||
428 | |||
429 | ## begin gnulib module strndup | ||
430 | |||
431 | |||
432 | EXTRA_DIST += strndup.c strndup.h | ||
433 | |||
434 | EXTRA_libgnu_a_SOURCES += strndup.c | ||
435 | |||
436 | ## end gnulib module strndup | ||
437 | |||
438 | ## begin gnulib module strnlen | ||
439 | |||
440 | |||
441 | EXTRA_DIST += strnlen.c strnlen.h | ||
442 | |||
443 | EXTRA_libgnu_a_SOURCES += strnlen.c | ||
444 | |||
445 | ## end gnulib module strnlen | ||
446 | |||
447 | ## begin gnulib module strnlen1 | ||
448 | |||
449 | libgnu_a_SOURCES += strnlen1.h strnlen1.c | ||
450 | |||
451 | ## end gnulib module strnlen1 | ||
452 | |||
453 | ## begin gnulib module sys_socket | ||
454 | |||
455 | BUILT_SOURCES += $(SYS_SOCKET_H) | ||
456 | |||
457 | # We need the following in order to create <sys/socket.h> when the system | ||
458 | # doesn't have one that works with the given compiler. | ||
459 | sys/socket.h: socket_.h | ||
460 | @MKDIR_P@ sys | ||
461 | { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ | ||
462 | cat $(srcdir)/socket_.h; \ | ||
463 | } > $@-t | ||
464 | mv -f $@-t $@ | ||
465 | MOSTLYCLEANFILES += sys/socket.h sys/socket.h-t | ||
466 | MOSTLYCLEANDIRS += sys | ||
467 | |||
468 | EXTRA_DIST += socket_.h | ||
469 | |||
470 | ## end gnulib module sys_socket | ||
471 | |||
472 | ## begin gnulib module unistd | ||
473 | |||
474 | BUILT_SOURCES += $(UNISTD_H) | ||
475 | |||
476 | # We need the following in order to create an empty placeholder for | ||
477 | # <unistd.h> when the system doesn't have one. | ||
478 | unistd.h: unistd_.h | ||
479 | rm -f $@-t $@ | ||
480 | { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ | ||
481 | sed -e 's|@''ABSOLUTE_UNISTD_H''@|$(ABSOLUTE_UNISTD_H)|g' \ | ||
482 | < $(srcdir)/unistd_.h; \ | ||
483 | } > $@-t | ||
484 | mv $@-t $@ | ||
485 | MOSTLYCLEANFILES += unistd.h unistd.h-t | ||
486 | |||
487 | EXTRA_DIST += unistd_.h | ||
488 | |||
489 | ## end gnulib module unistd | ||
490 | |||
491 | ## begin gnulib module unistd-safer | ||
492 | |||
493 | |||
494 | EXTRA_DIST += dup-safer.c fd-safer.c pipe-safer.c unistd--.h unistd-safer.h | ||
495 | |||
496 | EXTRA_libgnu_a_SOURCES += dup-safer.c fd-safer.c pipe-safer.c | ||
497 | |||
498 | ## end gnulib module unistd-safer | ||
499 | |||
500 | ## begin gnulib module vasnprintf | ||
501 | |||
502 | |||
503 | EXTRA_DIST += asnprintf.c printf-args.c printf-args.h printf-parse.c printf-parse.h vasnprintf.c vasnprintf.h | ||
504 | |||
505 | EXTRA_libgnu_a_SOURCES += asnprintf.c printf-args.c printf-parse.c vasnprintf.c | ||
506 | |||
507 | ## end gnulib module vasnprintf | ||
508 | |||
509 | ## begin gnulib module vasprintf | ||
510 | |||
511 | |||
512 | EXTRA_DIST += asprintf.c vasprintf.c vasprintf.h | ||
513 | |||
514 | EXTRA_libgnu_a_SOURCES += asprintf.c vasprintf.c | ||
515 | |||
516 | ## end gnulib module vasprintf | ||
517 | |||
518 | ## begin gnulib module vsnprintf | ||
519 | |||
520 | |||
521 | EXTRA_DIST += vsnprintf.c vsnprintf.h | ||
522 | |||
523 | EXTRA_libgnu_a_SOURCES += vsnprintf.c | ||
524 | |||
525 | ## end gnulib module vsnprintf | ||
526 | |||
527 | ## begin gnulib module wchar | ||
528 | |||
529 | BUILT_SOURCES += $(WCHAR_H) | ||
530 | |||
531 | # We need the following in order to create <wchar.h> when the system | ||
532 | # version does not work standalone. | ||
533 | wchar.h: wchar_.h | ||
534 | rm -f $@-t $@ | ||
535 | { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ | ||
536 | sed -e 's|@''ABSOLUTE_WCHAR_H''@|$(ABSOLUTE_WCHAR_H)|g' \ | ||
537 | < $(srcdir)/wchar_.h; \ | ||
538 | } > $@-t | ||
539 | mv $@-t $@ | ||
540 | MOSTLYCLEANFILES += wchar.h wchar.h-t | ||
541 | |||
542 | EXTRA_DIST += wchar_.h | ||
543 | |||
544 | ## end gnulib module wchar | ||
545 | |||
546 | ## begin gnulib module wctype | ||
547 | |||
548 | BUILT_SOURCES += $(WCTYPE_H) | ||
549 | |||
550 | # We need the following in order to create <wctype.h> when the system | ||
551 | # doesn't have one that works with the given compiler. | ||
552 | wctype.h: wctype_.h | ||
553 | rm -f $@-t $@ | ||
554 | { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ | ||
555 | sed -e 's/@''HAVE_WCTYPE_H''@/$(HAVE_WCTYPE_H)/g' \ | ||
556 | -e 's|@''ABSOLUTE_WCTYPE_H''@|$(ABSOLUTE_WCTYPE_H)|g' \ | ||
557 | -e 's/@''HAVE_WCTYPE_CTMP_BUG''@/$(HAVE_WCTYPE_CTMP_BUG)/g' \ | ||
558 | -e 's/@''HAVE_WINT_T''@/$(HAVE_WINT_T)/g' \ | ||
559 | < $(srcdir)/wctype_.h; \ | ||
560 | } > $@-t | ||
561 | mv $@-t $@ | ||
562 | MOSTLYCLEANFILES += wctype.h wctype.h-t | ||
563 | |||
564 | EXTRA_DIST += wctype_.h | ||
565 | |||
566 | ## end gnulib module wctype | ||
567 | |||
568 | ## begin gnulib module wcwidth | ||
569 | |||
570 | libgnu_a_SOURCES += wcwidth.h | ||
571 | |||
572 | ## end gnulib module wcwidth | ||
573 | |||
574 | ## begin gnulib module xalloc | ||
575 | |||
576 | |||
577 | EXTRA_DIST += xalloc.h xmalloc.c | ||
578 | |||
579 | EXTRA_libgnu_a_SOURCES += xmalloc.c | ||
580 | |||
581 | ## end gnulib module xalloc | ||
582 | |||
583 | ## begin gnulib module xalloc-die | ||
584 | |||
585 | libgnu_a_SOURCES += xalloc-die.c | ||
586 | |||
587 | ## end gnulib module xalloc-die | ||
588 | |||
589 | ## begin gnulib module xsize | ||
590 | |||
591 | libgnu_a_SOURCES += xsize.h | ||
592 | |||
593 | ## end gnulib module xsize | ||
594 | |||
595 | ## begin gnulib module xstrndup | ||
596 | |||
597 | libgnu_a_SOURCES += xstrndup.h xstrndup.c | ||
598 | |||
599 | ## end gnulib module xstrndup | ||
600 | |||
601 | |||
602 | mostlyclean-local: mostlyclean-generic | ||
603 | @for dir in '' $(MOSTLYCLEANDIRS); do \ | ||
604 | if test -n "$$dir" && test -d $$dir; then \ | ||
605 | echo "rmdir $$dir"; rmdir $$dir; \ | ||
606 | fi; \ | ||
607 | done | ||
diff --git a/gl/alloca.c b/gl/alloca.c new file mode 100644 index 00000000..3a1f4e27 --- /dev/null +++ b/gl/alloca.c | |||
@@ -0,0 +1,489 @@ | |||
1 | /* alloca.c -- allocate automatically reclaimed memory | ||
2 | (Mostly) portable public-domain implementation -- D A Gwyn | ||
3 | |||
4 | This implementation of the PWB library alloca function, | ||
5 | which is used to allocate space off the run-time stack so | ||
6 | that it is automatically reclaimed upon procedure exit, | ||
7 | was inspired by discussions with J. Q. Johnson of Cornell. | ||
8 | J.Otto Tennant <jot@cray.com> contributed the Cray support. | ||
9 | |||
10 | There are some preprocessor constants that can | ||
11 | be defined when compiling for your specific system, for | ||
12 | improved efficiency; however, the defaults should be okay. | ||
13 | |||
14 | The general concept of this implementation is to keep | ||
15 | track of all alloca-allocated blocks, and reclaim any | ||
16 | that are found to be deeper in the stack than the current | ||
17 | invocation. This heuristic does not reclaim storage as | ||
18 | soon as it becomes invalid, but it will do so eventually. | ||
19 | |||
20 | As a special case, alloca(0) reclaims storage without | ||
21 | allocating any. It is a good idea to use alloca(0) in | ||
22 | your main control loop, etc. to force garbage collection. */ | ||
23 | |||
24 | #include <config.h> | ||
25 | |||
26 | #include <alloca.h> | ||
27 | |||
28 | #include <string.h> | ||
29 | #include <stdlib.h> | ||
30 | |||
31 | #ifdef emacs | ||
32 | # include "lisp.h" | ||
33 | # include "blockinput.h" | ||
34 | # ifdef EMACS_FREE | ||
35 | # undef free | ||
36 | # define free EMACS_FREE | ||
37 | # endif | ||
38 | #else | ||
39 | # define memory_full() abort () | ||
40 | #endif | ||
41 | |||
42 | /* If compiling with GCC 2, this file's not needed. */ | ||
43 | #if !defined (__GNUC__) || __GNUC__ < 2 | ||
44 | |||
45 | /* If someone has defined alloca as a macro, | ||
46 | there must be some other way alloca is supposed to work. */ | ||
47 | # ifndef alloca | ||
48 | |||
49 | # ifdef emacs | ||
50 | # ifdef static | ||
51 | /* actually, only want this if static is defined as "" | ||
52 | -- this is for usg, in which emacs must undefine static | ||
53 | in order to make unexec workable | ||
54 | */ | ||
55 | # ifndef STACK_DIRECTION | ||
56 | you | ||
57 | lose | ||
58 | -- must know STACK_DIRECTION at compile-time | ||
59 | /* Using #error here is not wise since this file should work for | ||
60 | old and obscure compilers. */ | ||
61 | # endif /* STACK_DIRECTION undefined */ | ||
62 | # endif /* static */ | ||
63 | # endif /* emacs */ | ||
64 | |||
65 | /* If your stack is a linked list of frames, you have to | ||
66 | provide an "address metric" ADDRESS_FUNCTION macro. */ | ||
67 | |||
68 | # if defined (CRAY) && defined (CRAY_STACKSEG_END) | ||
69 | long i00afunc (); | ||
70 | # define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg)) | ||
71 | # else | ||
72 | # define ADDRESS_FUNCTION(arg) &(arg) | ||
73 | # endif | ||
74 | |||
75 | /* Define STACK_DIRECTION if you know the direction of stack | ||
76 | growth for your system; otherwise it will be automatically | ||
77 | deduced at run-time. | ||
78 | |||
79 | STACK_DIRECTION > 0 => grows toward higher addresses | ||
80 | STACK_DIRECTION < 0 => grows toward lower addresses | ||
81 | STACK_DIRECTION = 0 => direction of growth unknown */ | ||
82 | |||
83 | # ifndef STACK_DIRECTION | ||
84 | # define STACK_DIRECTION 0 /* Direction unknown. */ | ||
85 | # endif | ||
86 | |||
87 | # if STACK_DIRECTION != 0 | ||
88 | |||
89 | # define STACK_DIR STACK_DIRECTION /* Known at compile-time. */ | ||
90 | |||
91 | # else /* STACK_DIRECTION == 0; need run-time code. */ | ||
92 | |||
93 | static int stack_dir; /* 1 or -1 once known. */ | ||
94 | # define STACK_DIR stack_dir | ||
95 | |||
96 | static void | ||
97 | find_stack_direction (void) | ||
98 | { | ||
99 | static char *addr = NULL; /* Address of first `dummy', once known. */ | ||
100 | auto char dummy; /* To get stack address. */ | ||
101 | |||
102 | if (addr == NULL) | ||
103 | { /* Initial entry. */ | ||
104 | addr = ADDRESS_FUNCTION (dummy); | ||
105 | |||
106 | find_stack_direction (); /* Recurse once. */ | ||
107 | } | ||
108 | else | ||
109 | { | ||
110 | /* Second entry. */ | ||
111 | if (ADDRESS_FUNCTION (dummy) > addr) | ||
112 | stack_dir = 1; /* Stack grew upward. */ | ||
113 | else | ||
114 | stack_dir = -1; /* Stack grew downward. */ | ||
115 | } | ||
116 | } | ||
117 | |||
118 | # endif /* STACK_DIRECTION == 0 */ | ||
119 | |||
120 | /* An "alloca header" is used to: | ||
121 | (a) chain together all alloca'ed blocks; | ||
122 | (b) keep track of stack depth. | ||
123 | |||
124 | It is very important that sizeof(header) agree with malloc | ||
125 | alignment chunk size. The following default should work okay. */ | ||
126 | |||
127 | # ifndef ALIGN_SIZE | ||
128 | # define ALIGN_SIZE sizeof(double) | ||
129 | # endif | ||
130 | |||
131 | typedef union hdr | ||
132 | { | ||
133 | char align[ALIGN_SIZE]; /* To force sizeof(header). */ | ||
134 | struct | ||
135 | { | ||
136 | union hdr *next; /* For chaining headers. */ | ||
137 | char *deep; /* For stack depth measure. */ | ||
138 | } h; | ||
139 | } header; | ||
140 | |||
141 | static header *last_alloca_header = NULL; /* -> last alloca header. */ | ||
142 | |||
143 | /* Return a pointer to at least SIZE bytes of storage, | ||
144 | which will be automatically reclaimed upon exit from | ||
145 | the procedure that called alloca. Originally, this space | ||
146 | was supposed to be taken from the current stack frame of the | ||
147 | caller, but that method cannot be made to work for some | ||
148 | implementations of C, for example under Gould's UTX/32. */ | ||
149 | |||
150 | void * | ||
151 | alloca (size_t size) | ||
152 | { | ||
153 | auto char probe; /* Probes stack depth: */ | ||
154 | register char *depth = ADDRESS_FUNCTION (probe); | ||
155 | |||
156 | # if STACK_DIRECTION == 0 | ||
157 | if (STACK_DIR == 0) /* Unknown growth direction. */ | ||
158 | find_stack_direction (); | ||
159 | # endif | ||
160 | |||
161 | /* Reclaim garbage, defined as all alloca'd storage that | ||
162 | was allocated from deeper in the stack than currently. */ | ||
163 | |||
164 | { | ||
165 | register header *hp; /* Traverses linked list. */ | ||
166 | |||
167 | # ifdef emacs | ||
168 | BLOCK_INPUT; | ||
169 | # endif | ||
170 | |||
171 | for (hp = last_alloca_header; hp != NULL;) | ||
172 | if ((STACK_DIR > 0 && hp->h.deep > depth) | ||
173 | || (STACK_DIR < 0 && hp->h.deep < depth)) | ||
174 | { | ||
175 | register header *np = hp->h.next; | ||
176 | |||
177 | free (hp); /* Collect garbage. */ | ||
178 | |||
179 | hp = np; /* -> next header. */ | ||
180 | } | ||
181 | else | ||
182 | break; /* Rest are not deeper. */ | ||
183 | |||
184 | last_alloca_header = hp; /* -> last valid storage. */ | ||
185 | |||
186 | # ifdef emacs | ||
187 | UNBLOCK_INPUT; | ||
188 | # endif | ||
189 | } | ||
190 | |||
191 | if (size == 0) | ||
192 | return NULL; /* No allocation required. */ | ||
193 | |||
194 | /* Allocate combined header + user data storage. */ | ||
195 | |||
196 | { | ||
197 | /* Address of header. */ | ||
198 | register header *new; | ||
199 | |||
200 | size_t combined_size = sizeof (header) + size; | ||
201 | if (combined_size < sizeof (header)) | ||
202 | memory_full (); | ||
203 | |||
204 | new = malloc (combined_size); | ||
205 | |||
206 | if (! new) | ||
207 | memory_full (); | ||
208 | |||
209 | new->h.next = last_alloca_header; | ||
210 | new->h.deep = depth; | ||
211 | |||
212 | last_alloca_header = new; | ||
213 | |||
214 | /* User storage begins just after header. */ | ||
215 | |||
216 | return (void *) (new + 1); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | # if defined (CRAY) && defined (CRAY_STACKSEG_END) | ||
221 | |||
222 | # ifdef DEBUG_I00AFUNC | ||
223 | # include <stdio.h> | ||
224 | # endif | ||
225 | |||
226 | # ifndef CRAY_STACK | ||
227 | # define CRAY_STACK | ||
228 | # ifndef CRAY2 | ||
229 | /* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */ | ||
230 | struct stack_control_header | ||
231 | { | ||
232 | long shgrow:32; /* Number of times stack has grown. */ | ||
233 | long shaseg:32; /* Size of increments to stack. */ | ||
234 | long shhwm:32; /* High water mark of stack. */ | ||
235 | long shsize:32; /* Current size of stack (all segments). */ | ||
236 | }; | ||
237 | |||
238 | /* The stack segment linkage control information occurs at | ||
239 | the high-address end of a stack segment. (The stack | ||
240 | grows from low addresses to high addresses.) The initial | ||
241 | part of the stack segment linkage control information is | ||
242 | 0200 (octal) words. This provides for register storage | ||
243 | for the routine which overflows the stack. */ | ||
244 | |||
245 | struct stack_segment_linkage | ||
246 | { | ||
247 | long ss[0200]; /* 0200 overflow words. */ | ||
248 | long sssize:32; /* Number of words in this segment. */ | ||
249 | long ssbase:32; /* Offset to stack base. */ | ||
250 | long:32; | ||
251 | long sspseg:32; /* Offset to linkage control of previous | ||
252 | segment of stack. */ | ||
253 | long:32; | ||
254 | long sstcpt:32; /* Pointer to task common address block. */ | ||
255 | long sscsnm; /* Private control structure number for | ||
256 | microtasking. */ | ||
257 | long ssusr1; /* Reserved for user. */ | ||
258 | long ssusr2; /* Reserved for user. */ | ||
259 | long sstpid; /* Process ID for pid based multi-tasking. */ | ||
260 | long ssgvup; /* Pointer to multitasking thread giveup. */ | ||
261 | long sscray[7]; /* Reserved for Cray Research. */ | ||
262 | long ssa0; | ||
263 | long ssa1; | ||
264 | long ssa2; | ||
265 | long ssa3; | ||
266 | long ssa4; | ||
267 | long ssa5; | ||
268 | long ssa6; | ||
269 | long ssa7; | ||
270 | long sss0; | ||
271 | long sss1; | ||
272 | long sss2; | ||
273 | long sss3; | ||
274 | long sss4; | ||
275 | long sss5; | ||
276 | long sss6; | ||
277 | long sss7; | ||
278 | }; | ||
279 | |||
280 | # else /* CRAY2 */ | ||
281 | /* The following structure defines the vector of words | ||
282 | returned by the STKSTAT library routine. */ | ||
283 | struct stk_stat | ||
284 | { | ||
285 | long now; /* Current total stack size. */ | ||
286 | long maxc; /* Amount of contiguous space which would | ||
287 | be required to satisfy the maximum | ||
288 | stack demand to date. */ | ||
289 | long high_water; /* Stack high-water mark. */ | ||
290 | long overflows; /* Number of stack overflow ($STKOFEN) calls. */ | ||
291 | long hits; /* Number of internal buffer hits. */ | ||
292 | long extends; /* Number of block extensions. */ | ||
293 | long stko_mallocs; /* Block allocations by $STKOFEN. */ | ||
294 | long underflows; /* Number of stack underflow calls ($STKRETN). */ | ||
295 | long stko_free; /* Number of deallocations by $STKRETN. */ | ||
296 | long stkm_free; /* Number of deallocations by $STKMRET. */ | ||
297 | long segments; /* Current number of stack segments. */ | ||
298 | long maxs; /* Maximum number of stack segments so far. */ | ||
299 | long pad_size; /* Stack pad size. */ | ||
300 | long current_address; /* Current stack segment address. */ | ||
301 | long current_size; /* Current stack segment size. This | ||
302 | number is actually corrupted by STKSTAT to | ||
303 | include the fifteen word trailer area. */ | ||
304 | long initial_address; /* Address of initial segment. */ | ||
305 | long initial_size; /* Size of initial segment. */ | ||
306 | }; | ||
307 | |||
308 | /* The following structure describes the data structure which trails | ||
309 | any stack segment. I think that the description in 'asdef' is | ||
310 | out of date. I only describe the parts that I am sure about. */ | ||
311 | |||
312 | struct stk_trailer | ||
313 | { | ||
314 | long this_address; /* Address of this block. */ | ||
315 | long this_size; /* Size of this block (does not include | ||
316 | this trailer). */ | ||
317 | long unknown2; | ||
318 | long unknown3; | ||
319 | long link; /* Address of trailer block of previous | ||
320 | segment. */ | ||
321 | long unknown5; | ||
322 | long unknown6; | ||
323 | long unknown7; | ||
324 | long unknown8; | ||
325 | long unknown9; | ||
326 | long unknown10; | ||
327 | long unknown11; | ||
328 | long unknown12; | ||
329 | long unknown13; | ||
330 | long unknown14; | ||
331 | }; | ||
332 | |||
333 | # endif /* CRAY2 */ | ||
334 | # endif /* not CRAY_STACK */ | ||
335 | |||
336 | # ifdef CRAY2 | ||
337 | /* Determine a "stack measure" for an arbitrary ADDRESS. | ||
338 | I doubt that "lint" will like this much. */ | ||
339 | |||
340 | static long | ||
341 | i00afunc (long *address) | ||
342 | { | ||
343 | struct stk_stat status; | ||
344 | struct stk_trailer *trailer; | ||
345 | long *block, size; | ||
346 | long result = 0; | ||
347 | |||
348 | /* We want to iterate through all of the segments. The first | ||
349 | step is to get the stack status structure. We could do this | ||
350 | more quickly and more directly, perhaps, by referencing the | ||
351 | $LM00 common block, but I know that this works. */ | ||
352 | |||
353 | STKSTAT (&status); | ||
354 | |||
355 | /* Set up the iteration. */ | ||
356 | |||
357 | trailer = (struct stk_trailer *) (status.current_address | ||
358 | + status.current_size | ||
359 | - 15); | ||
360 | |||
361 | /* There must be at least one stack segment. Therefore it is | ||
362 | a fatal error if "trailer" is null. */ | ||
363 | |||
364 | if (trailer == 0) | ||
365 | abort (); | ||
366 | |||
367 | /* Discard segments that do not contain our argument address. */ | ||
368 | |||
369 | while (trailer != 0) | ||
370 | { | ||
371 | block = (long *) trailer->this_address; | ||
372 | size = trailer->this_size; | ||
373 | if (block == 0 || size == 0) | ||
374 | abort (); | ||
375 | trailer = (struct stk_trailer *) trailer->link; | ||
376 | if ((block <= address) && (address < (block + size))) | ||
377 | break; | ||
378 | } | ||
379 | |||
380 | /* Set the result to the offset in this segment and add the sizes | ||
381 | of all predecessor segments. */ | ||
382 | |||
383 | result = address - block; | ||
384 | |||
385 | if (trailer == 0) | ||
386 | { | ||
387 | return result; | ||
388 | } | ||
389 | |||
390 | do | ||
391 | { | ||
392 | if (trailer->this_size <= 0) | ||
393 | abort (); | ||
394 | result += trailer->this_size; | ||
395 | trailer = (struct stk_trailer *) trailer->link; | ||
396 | } | ||
397 | while (trailer != 0); | ||
398 | |||
399 | /* We are done. Note that if you present a bogus address (one | ||
400 | not in any segment), you will get a different number back, formed | ||
401 | from subtracting the address of the first block. This is probably | ||
402 | not what you want. */ | ||
403 | |||
404 | return (result); | ||
405 | } | ||
406 | |||
407 | # else /* not CRAY2 */ | ||
408 | /* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP. | ||
409 | Determine the number of the cell within the stack, | ||
410 | given the address of the cell. The purpose of this | ||
411 | routine is to linearize, in some sense, stack addresses | ||
412 | for alloca. */ | ||
413 | |||
414 | static long | ||
415 | i00afunc (long address) | ||
416 | { | ||
417 | long stkl = 0; | ||
418 | |||
419 | long size, pseg, this_segment, stack; | ||
420 | long result = 0; | ||
421 | |||
422 | struct stack_segment_linkage *ssptr; | ||
423 | |||
424 | /* Register B67 contains the address of the end of the | ||
425 | current stack segment. If you (as a subprogram) store | ||
426 | your registers on the stack and find that you are past | ||
427 | the contents of B67, you have overflowed the segment. | ||
428 | |||
429 | B67 also points to the stack segment linkage control | ||
430 | area, which is what we are really interested in. */ | ||
431 | |||
432 | stkl = CRAY_STACKSEG_END (); | ||
433 | ssptr = (struct stack_segment_linkage *) stkl; | ||
434 | |||
435 | /* If one subtracts 'size' from the end of the segment, | ||
436 | one has the address of the first word of the segment. | ||
437 | |||
438 | If this is not the first segment, 'pseg' will be | ||
439 | nonzero. */ | ||
440 | |||
441 | pseg = ssptr->sspseg; | ||
442 | size = ssptr->sssize; | ||
443 | |||
444 | this_segment = stkl - size; | ||
445 | |||
446 | /* It is possible that calling this routine itself caused | ||
447 | a stack overflow. Discard stack segments which do not | ||
448 | contain the target address. */ | ||
449 | |||
450 | while (!(this_segment <= address && address <= stkl)) | ||
451 | { | ||
452 | # ifdef DEBUG_I00AFUNC | ||
453 | fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl); | ||
454 | # endif | ||
455 | if (pseg == 0) | ||
456 | break; | ||
457 | stkl = stkl - pseg; | ||
458 | ssptr = (struct stack_segment_linkage *) stkl; | ||
459 | size = ssptr->sssize; | ||
460 | pseg = ssptr->sspseg; | ||
461 | this_segment = stkl - size; | ||
462 | } | ||
463 | |||
464 | result = address - this_segment; | ||
465 | |||
466 | /* If you subtract pseg from the current end of the stack, | ||
467 | you get the address of the previous stack segment's end. | ||
468 | This seems a little convoluted to me, but I'll bet you save | ||
469 | a cycle somewhere. */ | ||
470 | |||
471 | while (pseg != 0) | ||
472 | { | ||
473 | # ifdef DEBUG_I00AFUNC | ||
474 | fprintf (stderr, "%011o %011o\n", pseg, size); | ||
475 | # endif | ||
476 | stkl = stkl - pseg; | ||
477 | ssptr = (struct stack_segment_linkage *) stkl; | ||
478 | size = ssptr->sssize; | ||
479 | pseg = ssptr->sspseg; | ||
480 | result += size; | ||
481 | } | ||
482 | return (result); | ||
483 | } | ||
484 | |||
485 | # endif /* not CRAY2 */ | ||
486 | # endif /* CRAY */ | ||
487 | |||
488 | # endif /* no alloca */ | ||
489 | #endif /* not GCC version 2 */ | ||
diff --git a/gl/alloca_.h b/gl/alloca_.h new file mode 100644 index 00000000..dd0b3e98 --- /dev/null +++ b/gl/alloca_.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* Memory allocation on the stack. | ||
2 | |||
3 | Copyright (C) 1995, 1999, 2001, 2002, 2003, 2004, 2006 Free Software | ||
4 | Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify it | ||
7 | under the terms of the GNU General Public License as published | ||
8 | by the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public | ||
17 | License along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | ||
19 | USA. */ | ||
20 | |||
21 | /* Avoid using the symbol _ALLOCA_H here, as Bison assumes _ALLOCA_H | ||
22 | means there is a real alloca function. */ | ||
23 | #ifndef _GNULIB_ALLOCA_H | ||
24 | # define _GNULIB_ALLOCA_H | ||
25 | |||
26 | /* alloca (N) returns a pointer to N bytes of memory | ||
27 | allocated on the stack, which will last until the function returns. | ||
28 | Use of alloca should be avoided: | ||
29 | - inside arguments of function calls - undefined behaviour, | ||
30 | - in inline functions - the allocation may actually last until the | ||
31 | calling function returns, | ||
32 | - for huge N (say, N >= 65536) - you never know how large (or small) | ||
33 | the stack is, and when the stack cannot fulfill the memory allocation | ||
34 | request, the program just crashes. | ||
35 | */ | ||
36 | |||
37 | #ifndef alloca | ||
38 | # ifdef __GNUC__ | ||
39 | # define alloca __builtin_alloca | ||
40 | # elif defined _AIX | ||
41 | # define alloca __alloca | ||
42 | # elif defined _MSC_VER | ||
43 | # include <malloc.h> | ||
44 | # define alloca _alloca | ||
45 | # else | ||
46 | # include <stddef.h> | ||
47 | # ifdef __cplusplus | ||
48 | extern "C" | ||
49 | # endif | ||
50 | void *alloca (size_t); | ||
51 | # endif | ||
52 | #endif | ||
53 | |||
54 | #endif /* _GNULIB_ALLOCA_H */ | ||
diff --git a/gl/asnprintf.c b/gl/asnprintf.c new file mode 100644 index 00000000..26c3988b --- /dev/null +++ b/gl/asnprintf.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* Formatted output to strings. | ||
2 | Copyright (C) 1999, 2002, 2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #include <config.h> | ||
19 | |||
20 | /* Specification. */ | ||
21 | #include "vasnprintf.h" | ||
22 | |||
23 | #include <stdarg.h> | ||
24 | |||
25 | char * | ||
26 | asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...) | ||
27 | { | ||
28 | va_list args; | ||
29 | char *result; | ||
30 | |||
31 | va_start (args, format); | ||
32 | result = vasnprintf (resultbuf, lengthp, format, args); | ||
33 | va_end (args); | ||
34 | return result; | ||
35 | } | ||
diff --git a/gl/asprintf.c b/gl/asprintf.c new file mode 100644 index 00000000..29ac6cf2 --- /dev/null +++ b/gl/asprintf.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* Formatted output to strings. | ||
2 | Copyright (C) 1999, 2002, 2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #include <config.h> | ||
19 | |||
20 | /* Specification. */ | ||
21 | #include "vasprintf.h" | ||
22 | |||
23 | #include <stdarg.h> | ||
24 | |||
25 | int | ||
26 | asprintf (char **resultp, const char *format, ...) | ||
27 | { | ||
28 | va_list args; | ||
29 | int result; | ||
30 | |||
31 | va_start (args, format); | ||
32 | result = vasprintf (resultp, format, args); | ||
33 | va_end (args); | ||
34 | return result; | ||
35 | } | ||
diff --git a/gl/basename.c b/gl/basename.c new file mode 100644 index 00000000..fbe17ff9 --- /dev/null +++ b/gl/basename.c | |||
@@ -0,0 +1,129 @@ | |||
1 | /* basename.c -- return the last element in a file name | ||
2 | |||
3 | Copyright (C) 1990, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 Free | ||
4 | Software Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | #include "dirname.h" | ||
23 | |||
24 | #include <string.h> | ||
25 | #include "xalloc.h" | ||
26 | #include "xstrndup.h" | ||
27 | |||
28 | /* Return the address of the last file name component of NAME. If | ||
29 | NAME has no relative file name components because it is a file | ||
30 | system root, return the empty string. */ | ||
31 | |||
32 | char * | ||
33 | last_component (char const *name) | ||
34 | { | ||
35 | char const *base = name + FILE_SYSTEM_PREFIX_LEN (name); | ||
36 | char const *p; | ||
37 | bool saw_slash = false; | ||
38 | |||
39 | while (ISSLASH (*base)) | ||
40 | base++; | ||
41 | |||
42 | for (p = base; *p; p++) | ||
43 | { | ||
44 | if (ISSLASH (*p)) | ||
45 | saw_slash = true; | ||
46 | else if (saw_slash) | ||
47 | { | ||
48 | base = p; | ||
49 | saw_slash = false; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | return (char *) base; | ||
54 | } | ||
55 | |||
56 | |||
57 | /* In general, we can't use the builtin `basename' function if available, | ||
58 | since it has different meanings in different environments. | ||
59 | In some environments the builtin `basename' modifies its argument. | ||
60 | |||
61 | Return the last file name component of NAME, allocated with | ||
62 | xmalloc. On systems with drive letters, a leading "./" | ||
63 | distinguishes relative names that would otherwise look like a drive | ||
64 | letter. Unlike POSIX basename(), NAME cannot be NULL, | ||
65 | base_name("") returns "", and the first trailing slash is not | ||
66 | stripped. | ||
67 | |||
68 | If lstat (NAME) would succeed, then { chdir (dir_name (NAME)); | ||
69 | lstat (base_name (NAME)); } will access the same file. Likewise, | ||
70 | if the sequence { chdir (dir_name (NAME)); | ||
71 | rename (base_name (NAME), "foo"); } succeeds, you have renamed NAME | ||
72 | to "foo" in the same directory NAME was in. */ | ||
73 | |||
74 | char * | ||
75 | base_name (char const *name) | ||
76 | { | ||
77 | char const *base = last_component (name); | ||
78 | size_t length; | ||
79 | |||
80 | /* If there is no last component, then name is a file system root or the | ||
81 | empty string. */ | ||
82 | if (! *base) | ||
83 | return xstrndup (name, base_len (name)); | ||
84 | |||
85 | /* Collapse a sequence of trailing slashes into one. */ | ||
86 | length = base_len (base); | ||
87 | if (ISSLASH (base[length])) | ||
88 | length++; | ||
89 | |||
90 | /* On systems with drive letters, `a/b:c' must return `./b:c' rather | ||
91 | than `b:c' to avoid confusion with a drive letter. On systems | ||
92 | with pure POSIX semantics, this is not an issue. */ | ||
93 | if (FILE_SYSTEM_PREFIX_LEN (base)) | ||
94 | { | ||
95 | char *p = xmalloc (length + 3); | ||
96 | p[0] = '.'; | ||
97 | p[1] = '/'; | ||
98 | memcpy (p + 2, base, length); | ||
99 | p[length + 2] = '\0'; | ||
100 | return p; | ||
101 | } | ||
102 | |||
103 | /* Finally, copy the basename. */ | ||
104 | return xstrndup (base, length); | ||
105 | } | ||
106 | |||
107 | /* Return the length of the basename NAME. Typically NAME is the | ||
108 | value returned by base_name or last_component. Act like strlen | ||
109 | (NAME), except omit all trailing slashes. */ | ||
110 | |||
111 | size_t | ||
112 | base_len (char const *name) | ||
113 | { | ||
114 | size_t len; | ||
115 | size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name); | ||
116 | |||
117 | for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--) | ||
118 | continue; | ||
119 | |||
120 | if (DOUBLE_SLASH_IS_DISTINCT_ROOT && len == 1 | ||
121 | && ISSLASH (name[0]) && ISSLASH (name[1]) && ! name[2]) | ||
122 | return 2; | ||
123 | |||
124 | if (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE && prefix_len | ||
125 | && len == prefix_len && ISSLASH (name[prefix_len])) | ||
126 | return prefix_len + 1; | ||
127 | |||
128 | return len; | ||
129 | } | ||
diff --git a/gl/c-strtod.c b/gl/c-strtod.c new file mode 100644 index 00000000..2234ed0f --- /dev/null +++ b/gl/c-strtod.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* Convert string to double, using the C locale. | ||
2 | |||
3 | Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Paul Eggert. */ | ||
20 | |||
21 | #include <config.h> | ||
22 | |||
23 | #include "c-strtod.h" | ||
24 | |||
25 | #include <locale.h> | ||
26 | #include <stdlib.h> | ||
27 | |||
28 | #include "xalloc.h" | ||
29 | |||
30 | #if LONG | ||
31 | # define C_STRTOD c_strtold | ||
32 | # define DOUBLE long double | ||
33 | # define STRTOD_L strtold_l | ||
34 | #else | ||
35 | # define C_STRTOD c_strtod | ||
36 | # define DOUBLE double | ||
37 | # define STRTOD_L strtod_l | ||
38 | #endif | ||
39 | |||
40 | /* c_strtold falls back on strtod if strtold doesn't conform to C99. */ | ||
41 | #if LONG && HAVE_C99_STRTOLD | ||
42 | # define STRTOD strtold | ||
43 | #else | ||
44 | # define STRTOD strtod | ||
45 | #endif | ||
46 | |||
47 | DOUBLE | ||
48 | C_STRTOD (char const *nptr, char **endptr) | ||
49 | { | ||
50 | DOUBLE r; | ||
51 | |||
52 | #ifdef LC_ALL_MASK | ||
53 | |||
54 | locale_t c_locale = newlocale (LC_ALL_MASK, "C", 0); | ||
55 | r = STRTOD_L (nptr, endptr, c_locale); | ||
56 | freelocale (c_locale); | ||
57 | |||
58 | #else | ||
59 | |||
60 | char *saved_locale = setlocale (LC_NUMERIC, NULL); | ||
61 | |||
62 | if (saved_locale) | ||
63 | { | ||
64 | saved_locale = xstrdup (saved_locale); | ||
65 | setlocale (LC_NUMERIC, "C"); | ||
66 | } | ||
67 | |||
68 | r = STRTOD (nptr, endptr); | ||
69 | |||
70 | if (saved_locale) | ||
71 | { | ||
72 | setlocale (LC_NUMERIC, saved_locale); | ||
73 | free (saved_locale); | ||
74 | } | ||
75 | |||
76 | #endif | ||
77 | |||
78 | return r; | ||
79 | } | ||
diff --git a/gl/c-strtod.h b/gl/c-strtod.h new file mode 100644 index 00000000..ca9a9e7c --- /dev/null +++ b/gl/c-strtod.h | |||
@@ -0,0 +1,2 @@ | |||
1 | double c_strtod (char const *, char **); | ||
2 | long double c_strtold (char const *, char **); | ||
diff --git a/gl/cloexec.c b/gl/cloexec.c new file mode 100644 index 00000000..6480006a --- /dev/null +++ b/gl/cloexec.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* closexec.c - set or clear the close-on-exec descriptor flag | ||
2 | |||
3 | Copyright (C) 1991, 2004, 2005, 2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
18 | |||
19 | The code is taken from glibc/manual/llio.texi */ | ||
20 | |||
21 | #include <config.h> | ||
22 | |||
23 | #include "cloexec.h" | ||
24 | |||
25 | #include <unistd.h> | ||
26 | #include <fcntl.h> | ||
27 | |||
28 | #ifndef FD_CLOEXEC | ||
29 | # define FD_CLOEXEC 1 | ||
30 | #endif | ||
31 | |||
32 | /* Set the `FD_CLOEXEC' flag of DESC if VALUE is true, | ||
33 | or clear the flag if VALUE is false. | ||
34 | Return 0 on success, or -1 on error with `errno' set. */ | ||
35 | |||
36 | int | ||
37 | set_cloexec_flag (int desc, bool value) | ||
38 | { | ||
39 | #if defined F_GETFD && defined F_SETFD | ||
40 | |||
41 | int flags = fcntl (desc, F_GETFD, 0); | ||
42 | |||
43 | if (0 <= flags) | ||
44 | { | ||
45 | int newflags = (value ? flags | FD_CLOEXEC : flags & ~FD_CLOEXEC); | ||
46 | |||
47 | if (flags == newflags | ||
48 | || fcntl (desc, F_SETFD, newflags) != -1) | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | return -1; | ||
53 | |||
54 | #else | ||
55 | |||
56 | return 0; | ||
57 | |||
58 | #endif | ||
59 | } | ||
diff --git a/gl/cloexec.h b/gl/cloexec.h new file mode 100644 index 00000000..c25921d6 --- /dev/null +++ b/gl/cloexec.h | |||
@@ -0,0 +1,2 @@ | |||
1 | #include <stdbool.h> | ||
2 | int set_cloexec_flag (int desc, bool value); | ||
diff --git a/gl/creat-safer.c b/gl/creat-safer.c new file mode 100644 index 00000000..f4a2e59d --- /dev/null +++ b/gl/creat-safer.c | |||
@@ -0,0 +1,32 @@ | |||
1 | /* Invoke creat, but avoid some glitches. | ||
2 | |||
3 | Copyright (C) 2005, 2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Jim Meyering. */ | ||
20 | |||
21 | #include <config.h> | ||
22 | |||
23 | #include "fcntl-safer.h" | ||
24 | |||
25 | #include <fcntl.h> | ||
26 | #include "unistd-safer.h" | ||
27 | |||
28 | int | ||
29 | creat_safer (char const *file, mode_t mode) | ||
30 | { | ||
31 | return fd_safer (creat (file, mode)); | ||
32 | } | ||
diff --git a/gl/dirname.c b/gl/dirname.c new file mode 100644 index 00000000..16552c64 --- /dev/null +++ b/gl/dirname.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* dirname.c -- return all but the last element in a file name | ||
2 | |||
3 | Copyright (C) 1990, 1998, 2000, 2001, 2003, 2004, 2005, 2006 Free Software | ||
4 | Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | #include "dirname.h" | ||
23 | |||
24 | #include <string.h> | ||
25 | #include "xalloc.h" | ||
26 | |||
27 | /* Return the length of the prefix of FILE that will be used by | ||
28 | dir_name. If FILE is in the working directory, this returns zero | ||
29 | even though `dir_name (FILE)' will return ".". Works properly even | ||
30 | if there are trailing slashes (by effectively ignoring them). */ | ||
31 | |||
32 | size_t | ||
33 | dir_len (char const *file) | ||
34 | { | ||
35 | size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file); | ||
36 | size_t length; | ||
37 | |||
38 | /* Advance prefix_length beyond important leading slashes. */ | ||
39 | prefix_length += (prefix_length != 0 | ||
40 | ? (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE | ||
41 | && ISSLASH (file[prefix_length])) | ||
42 | : (ISSLASH (file[0]) | ||
43 | ? ((DOUBLE_SLASH_IS_DISTINCT_ROOT | ||
44 | && ISSLASH (file[1]) && ! ISSLASH (file[2]) | ||
45 | ? 2 : 1)) | ||
46 | : 0)); | ||
47 | |||
48 | /* Strip the basename and any redundant slashes before it. */ | ||
49 | for (length = last_component (file) - file; | ||
50 | prefix_length < length; length--) | ||
51 | if (! ISSLASH (file[length - 1])) | ||
52 | break; | ||
53 | return length; | ||
54 | } | ||
55 | |||
56 | |||
57 | /* In general, we can't use the builtin `dirname' function if available, | ||
58 | since it has different meanings in different environments. | ||
59 | In some environments the builtin `dirname' modifies its argument. | ||
60 | |||
61 | Return the leading directories part of FILE, allocated with xmalloc. | ||
62 | Works properly even if there are trailing slashes (by effectively | ||
63 | ignoring them). Unlike POSIX dirname(), FILE cannot be NULL. | ||
64 | |||
65 | If lstat (FILE) would succeed, then { chdir (dir_name (FILE)); | ||
66 | lstat (base_name (FILE)); } will access the same file. Likewise, | ||
67 | if the sequence { chdir (dir_name (FILE)); | ||
68 | rename (base_name (FILE), "foo"); } succeeds, you have renamed FILE | ||
69 | to "foo" in the same directory FILE was in. */ | ||
70 | |||
71 | char * | ||
72 | dir_name (char const *file) | ||
73 | { | ||
74 | size_t length = dir_len (file); | ||
75 | bool append_dot = (length == 0 | ||
76 | || (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE | ||
77 | && length == FILE_SYSTEM_PREFIX_LEN (file) | ||
78 | && file[2] != '\0' && ! ISSLASH (file[2]))); | ||
79 | char *dir = xmalloc (length + append_dot + 1); | ||
80 | memcpy (dir, file, length); | ||
81 | if (append_dot) | ||
82 | dir[length++] = '.'; | ||
83 | dir[length] = '\0'; | ||
84 | return dir; | ||
85 | } | ||
diff --git a/gl/dirname.h b/gl/dirname.h new file mode 100644 index 00000000..91e7ed33 --- /dev/null +++ b/gl/dirname.h | |||
@@ -0,0 +1,70 @@ | |||
1 | /* Take file names apart into directory and base names. | ||
2 | |||
3 | Copyright (C) 1998, 2001, 2003-2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #ifndef DIRNAME_H_ | ||
20 | # define DIRNAME_H_ 1 | ||
21 | |||
22 | # include <stdbool.h> | ||
23 | # include <stddef.h> | ||
24 | |||
25 | # ifndef DIRECTORY_SEPARATOR | ||
26 | # define DIRECTORY_SEPARATOR '/' | ||
27 | # endif | ||
28 | |||
29 | # ifndef ISSLASH | ||
30 | # define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) | ||
31 | # endif | ||
32 | |||
33 | # ifndef FILE_SYSTEM_PREFIX_LEN | ||
34 | # if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX | ||
35 | /* This internal macro assumes ASCII, but all hosts that support drive | ||
36 | letters use ASCII. */ | ||
37 | # define _IS_DRIVE_LETTER(c) (((unsigned int) (c) | ('a' - 'A')) - 'a' \ | ||
38 | <= 'z' - 'a') | ||
39 | # define FILE_SYSTEM_PREFIX_LEN(Filename) \ | ||
40 | (_IS_DRIVE_LETTER ((Filename)[0]) && (Filename)[1] == ':' ? 2 : 0) | ||
41 | # else | ||
42 | # define FILE_SYSTEM_PREFIX_LEN(Filename) 0 | ||
43 | # endif | ||
44 | # endif | ||
45 | |||
46 | # ifndef FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE | ||
47 | # define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0 | ||
48 | # endif | ||
49 | |||
50 | # ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT | ||
51 | # define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 | ||
52 | # endif | ||
53 | |||
54 | # if FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE | ||
55 | # define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)]) | ||
56 | # else | ||
57 | # define IS_ABSOLUTE_FILE_NAME(F) \ | ||
58 | (ISSLASH ((F)[0]) || 0 < FILE_SYSTEM_PREFIX_LEN (F)) | ||
59 | # endif | ||
60 | # define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F)) | ||
61 | |||
62 | char *base_name (char const *file); | ||
63 | char *dir_name (char const *file); | ||
64 | size_t base_len (char const *file); | ||
65 | size_t dir_len (char const *file); | ||
66 | char *last_component (char const *file); | ||
67 | |||
68 | bool strip_trailing_slashes (char *file); | ||
69 | |||
70 | #endif /* not DIRNAME_H_ */ | ||
diff --git a/gl/dup-safer.c b/gl/dup-safer.c new file mode 100644 index 00000000..7b12b615 --- /dev/null +++ b/gl/dup-safer.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /* Invoke dup, but avoid some glitches. | ||
2 | |||
3 | Copyright (C) 2001, 2004, 2005, 2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Paul Eggert. */ | ||
20 | |||
21 | #include <config.h> | ||
22 | |||
23 | #include "unistd-safer.h" | ||
24 | |||
25 | #include <fcntl.h> | ||
26 | |||
27 | #include <unistd.h> | ||
28 | #ifndef STDERR_FILENO | ||
29 | # define STDERR_FILENO 2 | ||
30 | #endif | ||
31 | |||
32 | /* Like dup, but do not return STDIN_FILENO, STDOUT_FILENO, or | ||
33 | STDERR_FILENO. */ | ||
34 | |||
35 | int | ||
36 | dup_safer (int fd) | ||
37 | { | ||
38 | #if defined F_DUPFD && !defined FCHDIR_REPLACEMENT | ||
39 | return fcntl (fd, F_DUPFD, STDERR_FILENO + 1); | ||
40 | #else | ||
41 | /* fd_safer calls us back, but eventually the recursion unwinds and | ||
42 | does the right thing. */ | ||
43 | return fd_safer (dup (fd)); | ||
44 | #endif | ||
45 | } | ||
diff --git a/gl/error.c b/gl/error.c new file mode 100644 index 00000000..cf863433 --- /dev/null +++ b/gl/error.c | |||
@@ -0,0 +1,338 @@ | |||
1 | /* Error handler for noninteractive utilities | ||
2 | Copyright (C) 1990-1998, 2000-2005, 2006 Free Software Foundation, Inc. | ||
3 | This file is part of the GNU C Library. | ||
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, or (at your option) | ||
8 | 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 along | ||
16 | with this program; if not, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ | ||
20 | |||
21 | #if !_LIBC | ||
22 | # include <config.h> | ||
23 | #endif | ||
24 | |||
25 | #include "error.h" | ||
26 | |||
27 | #include <stdarg.h> | ||
28 | #include <stdio.h> | ||
29 | #include <stdlib.h> | ||
30 | #include <string.h> | ||
31 | |||
32 | #if !_LIBC && ENABLE_NLS | ||
33 | # include "gettext.h" | ||
34 | #endif | ||
35 | |||
36 | #ifdef _LIBC | ||
37 | # include <libintl.h> | ||
38 | # include <stdbool.h> | ||
39 | # include <stdint.h> | ||
40 | # include <wchar.h> | ||
41 | # define mbsrtowcs __mbsrtowcs | ||
42 | #endif | ||
43 | |||
44 | #if USE_UNLOCKED_IO | ||
45 | # include "unlocked-io.h" | ||
46 | #endif | ||
47 | |||
48 | #ifndef _ | ||
49 | # define _(String) String | ||
50 | #endif | ||
51 | |||
52 | /* If NULL, error will flush stdout, then print on stderr the program | ||
53 | name, a colon and a space. Otherwise, error will call this | ||
54 | function without parameters instead. */ | ||
55 | void (*error_print_progname) (void); | ||
56 | |||
57 | /* This variable is incremented each time `error' is called. */ | ||
58 | unsigned int error_message_count; | ||
59 | |||
60 | #ifdef _LIBC | ||
61 | /* In the GNU C library, there is a predefined variable for this. */ | ||
62 | |||
63 | # define program_name program_invocation_name | ||
64 | # include <errno.h> | ||
65 | # include <limits.h> | ||
66 | # include <libio/libioP.h> | ||
67 | |||
68 | /* In GNU libc we want do not want to use the common name `error' directly. | ||
69 | Instead make it a weak alias. */ | ||
70 | extern void __error (int status, int errnum, const char *message, ...) | ||
71 | __attribute__ ((__format__ (__printf__, 3, 4))); | ||
72 | extern void __error_at_line (int status, int errnum, const char *file_name, | ||
73 | unsigned int line_number, const char *message, | ||
74 | ...) | ||
75 | __attribute__ ((__format__ (__printf__, 5, 6)));; | ||
76 | # define error __error | ||
77 | # define error_at_line __error_at_line | ||
78 | |||
79 | # include <libio/iolibio.h> | ||
80 | # define fflush(s) INTUSE(_IO_fflush) (s) | ||
81 | # undef putc | ||
82 | # define putc(c, fp) INTUSE(_IO_putc) (c, fp) | ||
83 | |||
84 | # include <bits/libc-lock.h> | ||
85 | |||
86 | #else /* not _LIBC */ | ||
87 | |||
88 | # if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P | ||
89 | # ifndef HAVE_DECL_STRERROR_R | ||
90 | "this configure-time declaration test was not run" | ||
91 | # endif | ||
92 | char *strerror_r (); | ||
93 | # endif | ||
94 | |||
95 | /* The calling program should define program_name and set it to the | ||
96 | name of the executing program. */ | ||
97 | extern char *program_name; | ||
98 | |||
99 | # if HAVE_STRERROR_R || defined strerror_r | ||
100 | # define __strerror_r strerror_r | ||
101 | # endif /* HAVE_STRERROR_R || defined strerror_r */ | ||
102 | #endif /* not _LIBC */ | ||
103 | |||
104 | static void | ||
105 | print_errno_message (int errnum) | ||
106 | { | ||
107 | char const *s; | ||
108 | |||
109 | #if defined HAVE_STRERROR_R || _LIBC | ||
110 | char errbuf[1024]; | ||
111 | # if STRERROR_R_CHAR_P || _LIBC | ||
112 | s = __strerror_r (errnum, errbuf, sizeof errbuf); | ||
113 | # else | ||
114 | if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0) | ||
115 | s = errbuf; | ||
116 | else | ||
117 | s = 0; | ||
118 | # endif | ||
119 | #else | ||
120 | s = strerror (errnum); | ||
121 | #endif | ||
122 | |||
123 | #if !_LIBC | ||
124 | if (! s) | ||
125 | s = _("Unknown system error"); | ||
126 | #endif | ||
127 | |||
128 | #if _LIBC | ||
129 | __fxprintf (NULL, ": %s", s); | ||
130 | #else | ||
131 | fprintf (stderr, ": %s", s); | ||
132 | #endif | ||
133 | } | ||
134 | |||
135 | static void | ||
136 | error_tail (int status, int errnum, const char *message, va_list args) | ||
137 | { | ||
138 | #if _LIBC | ||
139 | if (_IO_fwide (stderr, 0) > 0) | ||
140 | { | ||
141 | # define ALLOCA_LIMIT 2000 | ||
142 | size_t len = strlen (message) + 1; | ||
143 | wchar_t *wmessage = NULL; | ||
144 | mbstate_t st; | ||
145 | size_t res; | ||
146 | const char *tmp; | ||
147 | bool use_malloc = false; | ||
148 | |||
149 | while (1) | ||
150 | { | ||
151 | if (__libc_use_alloca (len * sizeof (wchar_t))) | ||
152 | wmessage = (wchar_t *) alloca (len * sizeof (wchar_t)); | ||
153 | else | ||
154 | { | ||
155 | if (!use_malloc) | ||
156 | wmessage = NULL; | ||
157 | |||
158 | wchar_t *p = (wchar_t *) realloc (wmessage, | ||
159 | len * sizeof (wchar_t)); | ||
160 | if (p == NULL) | ||
161 | { | ||
162 | free (wmessage); | ||
163 | fputws_unlocked (L"out of memory\n", stderr); | ||
164 | return; | ||
165 | } | ||
166 | wmessage = p; | ||
167 | use_malloc = true; | ||
168 | } | ||
169 | |||
170 | memset (&st, '\0', sizeof (st)); | ||
171 | tmp = message; | ||
172 | |||
173 | res = mbsrtowcs (wmessage, &tmp, len, &st); | ||
174 | if (res != len) | ||
175 | break; | ||
176 | |||
177 | if (__builtin_expect (len >= SIZE_MAX / 2, 0)) | ||
178 | { | ||
179 | /* This really should not happen if everything is fine. */ | ||
180 | res = (size_t) -1; | ||
181 | break; | ||
182 | } | ||
183 | |||
184 | len *= 2; | ||
185 | } | ||
186 | |||
187 | if (res == (size_t) -1) | ||
188 | { | ||
189 | /* The string cannot be converted. */ | ||
190 | if (use_malloc) | ||
191 | { | ||
192 | free (wmessage); | ||
193 | use_malloc = false; | ||
194 | } | ||
195 | wmessage = (wchar_t *) L"???"; | ||
196 | } | ||
197 | |||
198 | __vfwprintf (stderr, wmessage, args); | ||
199 | |||
200 | if (use_malloc) | ||
201 | free (wmessage); | ||
202 | } | ||
203 | else | ||
204 | #endif | ||
205 | vfprintf (stderr, message, args); | ||
206 | va_end (args); | ||
207 | |||
208 | ++error_message_count; | ||
209 | if (errnum) | ||
210 | print_errno_message (errnum); | ||
211 | #if _LIBC | ||
212 | __fxprintf (NULL, "\n"); | ||
213 | #else | ||
214 | putc ('\n', stderr); | ||
215 | #endif | ||
216 | fflush (stderr); | ||
217 | if (status) | ||
218 | exit (status); | ||
219 | } | ||
220 | |||
221 | |||
222 | /* Print the program name and error message MESSAGE, which is a printf-style | ||
223 | format string with optional args. | ||
224 | If ERRNUM is nonzero, print its corresponding system error message. | ||
225 | Exit with status STATUS if it is nonzero. */ | ||
226 | void | ||
227 | error (int status, int errnum, const char *message, ...) | ||
228 | { | ||
229 | va_list args; | ||
230 | |||
231 | #if defined _LIBC && defined __libc_ptf_call | ||
232 | /* We do not want this call to be cut short by a thread | ||
233 | cancellation. Therefore disable cancellation for now. */ | ||
234 | int state = PTHREAD_CANCEL_ENABLE; | ||
235 | __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), | ||
236 | 0); | ||
237 | #endif | ||
238 | |||
239 | fflush (stdout); | ||
240 | #ifdef _LIBC | ||
241 | _IO_flockfile (stderr); | ||
242 | #endif | ||
243 | if (error_print_progname) | ||
244 | (*error_print_progname) (); | ||
245 | else | ||
246 | { | ||
247 | #if _LIBC | ||
248 | __fxprintf (NULL, "%s: ", program_name); | ||
249 | #else | ||
250 | fprintf (stderr, "%s: ", program_name); | ||
251 | #endif | ||
252 | } | ||
253 | |||
254 | va_start (args, message); | ||
255 | error_tail (status, errnum, message, args); | ||
256 | |||
257 | #ifdef _LIBC | ||
258 | _IO_funlockfile (stderr); | ||
259 | # ifdef __libc_ptf_call | ||
260 | __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0); | ||
261 | # endif | ||
262 | #endif | ||
263 | } | ||
264 | |||
265 | /* Sometimes we want to have at most one error per line. This | ||
266 | variable controls whether this mode is selected or not. */ | ||
267 | int error_one_per_line; | ||
268 | |||
269 | void | ||
270 | error_at_line (int status, int errnum, const char *file_name, | ||
271 | unsigned int line_number, const char *message, ...) | ||
272 | { | ||
273 | va_list args; | ||
274 | |||
275 | if (error_one_per_line) | ||
276 | { | ||
277 | static const char *old_file_name; | ||
278 | static unsigned int old_line_number; | ||
279 | |||
280 | if (old_line_number == line_number | ||
281 | && (file_name == old_file_name | ||
282 | || strcmp (old_file_name, file_name) == 0)) | ||
283 | /* Simply return and print nothing. */ | ||
284 | return; | ||
285 | |||
286 | old_file_name = file_name; | ||
287 | old_line_number = line_number; | ||
288 | } | ||
289 | |||
290 | #if defined _LIBC && defined __libc_ptf_call | ||
291 | /* We do not want this call to be cut short by a thread | ||
292 | cancellation. Therefore disable cancellation for now. */ | ||
293 | int state = PTHREAD_CANCEL_ENABLE; | ||
294 | __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), | ||
295 | 0); | ||
296 | #endif | ||
297 | |||
298 | fflush (stdout); | ||
299 | #ifdef _LIBC | ||
300 | _IO_flockfile (stderr); | ||
301 | #endif | ||
302 | if (error_print_progname) | ||
303 | (*error_print_progname) (); | ||
304 | else | ||
305 | { | ||
306 | #if _LIBC | ||
307 | __fxprintf (NULL, "%s:", program_name); | ||
308 | #else | ||
309 | fprintf (stderr, "%s:", program_name); | ||
310 | #endif | ||
311 | } | ||
312 | |||
313 | #if _LIBC | ||
314 | __fxprintf (NULL, file_name != NULL ? "%s:%d: " : " ", | ||
315 | file_name, line_number); | ||
316 | #else | ||
317 | fprintf (stderr, file_name != NULL ? "%s:%d: " : " ", | ||
318 | file_name, line_number); | ||
319 | #endif | ||
320 | |||
321 | va_start (args, message); | ||
322 | error_tail (status, errnum, message, args); | ||
323 | |||
324 | #ifdef _LIBC | ||
325 | _IO_funlockfile (stderr); | ||
326 | # ifdef __libc_ptf_call | ||
327 | __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0); | ||
328 | # endif | ||
329 | #endif | ||
330 | } | ||
331 | |||
332 | #ifdef _LIBC | ||
333 | /* Make the weak alias. */ | ||
334 | # undef error | ||
335 | # undef error_at_line | ||
336 | weak_alias (__error, error) | ||
337 | weak_alias (__error_at_line, error_at_line) | ||
338 | #endif | ||
diff --git a/gl/error.h b/gl/error.h new file mode 100644 index 00000000..5a5f2476 --- /dev/null +++ b/gl/error.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* Declaration for error-reporting function | ||
2 | Copyright (C) 1995, 1996, 1997, 2003, 2006 Free Software Foundation, Inc. | ||
3 | This file is part of the GNU C Library. | ||
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, or (at your option) | ||
8 | 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 along | ||
16 | with this program; if not, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #ifndef _ERROR_H | ||
20 | #define _ERROR_H 1 | ||
21 | |||
22 | #ifndef __attribute__ | ||
23 | /* This feature is available in gcc versions 2.5 and later. */ | ||
24 | # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ | ||
25 | # define __attribute__(Spec) /* empty */ | ||
26 | # endif | ||
27 | /* The __-protected variants of `format' and `printf' attributes | ||
28 | are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ | ||
29 | # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) | ||
30 | # define __format__ format | ||
31 | # define __printf__ printf | ||
32 | # endif | ||
33 | #endif | ||
34 | |||
35 | #ifdef __cplusplus | ||
36 | extern "C" { | ||
37 | #endif | ||
38 | |||
39 | /* Print a message with `fprintf (stderr, FORMAT, ...)'; | ||
40 | if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). | ||
41 | If STATUS is nonzero, terminate the program with `exit (STATUS)'. */ | ||
42 | |||
43 | extern void error (int __status, int __errnum, const char *__format, ...) | ||
44 | __attribute__ ((__format__ (__printf__, 3, 4))); | ||
45 | |||
46 | extern void error_at_line (int __status, int __errnum, const char *__fname, | ||
47 | unsigned int __lineno, const char *__format, ...) | ||
48 | __attribute__ ((__format__ (__printf__, 5, 6))); | ||
49 | |||
50 | /* If NULL, error will flush stdout, then print on stderr the program | ||
51 | name, a colon and a space. Otherwise, error will call this | ||
52 | function without parameters instead. */ | ||
53 | extern void (*error_print_progname) (void); | ||
54 | |||
55 | /* This variable is incremented each time `error' is called. */ | ||
56 | extern unsigned int error_message_count; | ||
57 | |||
58 | /* Sometimes we want to have at most one error per line. This | ||
59 | variable controls whether this mode is selected or not. */ | ||
60 | extern int error_one_per_line; | ||
61 | |||
62 | #ifdef __cplusplus | ||
63 | } | ||
64 | #endif | ||
65 | |||
66 | #endif /* error.h */ | ||
diff --git a/gl/exit.h b/gl/exit.h new file mode 100644 index 00000000..e8f77388 --- /dev/null +++ b/gl/exit.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* exit() function. | ||
2 | Copyright (C) 1995, 2001 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _EXIT_H | ||
19 | #define _EXIT_H | ||
20 | |||
21 | /* Get exit() declaration. */ | ||
22 | #include <stdlib.h> | ||
23 | |||
24 | /* Some systems do not define EXIT_*, despite otherwise supporting C89. */ | ||
25 | #ifndef EXIT_SUCCESS | ||
26 | # define EXIT_SUCCESS 0 | ||
27 | #endif | ||
28 | #ifndef EXIT_FAILURE | ||
29 | # define EXIT_FAILURE 1 | ||
30 | #endif | ||
31 | |||
32 | #endif /* _EXIT_H */ | ||
diff --git a/gl/exitfail.c b/gl/exitfail.c new file mode 100644 index 00000000..97abc674 --- /dev/null +++ b/gl/exitfail.c | |||
@@ -0,0 +1,25 @@ | |||
1 | /* Failure exit status | ||
2 | |||
3 | Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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; see the file COPYING. | ||
17 | If not, write to the Free Software Foundation, | ||
18 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | #include "exitfail.h" | ||
23 | #include "exit.h" | ||
24 | |||
25 | int volatile exit_failure = EXIT_FAILURE; | ||
diff --git a/gl/exitfail.h b/gl/exitfail.h new file mode 100644 index 00000000..e46cf9c1 --- /dev/null +++ b/gl/exitfail.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* Failure exit status | ||
2 | |||
3 | Copyright (C) 2002 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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; see the file COPYING. | ||
17 | If not, write to the Free Software Foundation, | ||
18 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | extern int volatile exit_failure; | ||
diff --git a/gl/fcntl--.h b/gl/fcntl--.h new file mode 100644 index 00000000..51b869e6 --- /dev/null +++ b/gl/fcntl--.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* Like fcntl.h, but redefine some names to avoid glitches. | ||
2 | |||
3 | Copyright (C) 2005 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Paul Eggert. */ | ||
20 | |||
21 | #include <fcntl.h> | ||
22 | #include "fcntl-safer.h" | ||
23 | |||
24 | #undef open | ||
25 | #define open open_safer | ||
26 | |||
27 | #undef creat | ||
28 | #define creat creat_safer | ||
diff --git a/gl/fcntl-safer.h b/gl/fcntl-safer.h new file mode 100644 index 00000000..cab6aab1 --- /dev/null +++ b/gl/fcntl-safer.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* Invoke fcntl-like functions, but avoid some glitches. | ||
2 | |||
3 | Copyright (C) 2005 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Paul Eggert. */ | ||
20 | |||
21 | #include <sys/types.h> | ||
22 | |||
23 | int open_safer (char const *, int, ...); | ||
24 | int creat_safer (char const *, mode_t); | ||
diff --git a/gl/fd-safer.c b/gl/fd-safer.c new file mode 100644 index 00000000..256bfa4a --- /dev/null +++ b/gl/fd-safer.c | |||
@@ -0,0 +1,57 @@ | |||
1 | /* Return a safer copy of a file descriptor. | ||
2 | |||
3 | Copyright (C) 2005, 2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Paul Eggert. */ | ||
20 | |||
21 | #include <config.h> | ||
22 | |||
23 | #include "unistd-safer.h" | ||
24 | |||
25 | #include <errno.h> | ||
26 | |||
27 | #include <unistd.h> | ||
28 | #ifndef STDIN_FILENO | ||
29 | # define STDIN_FILENO 0 | ||
30 | #endif | ||
31 | #ifndef STDERR_FILENO | ||
32 | # define STDERR_FILENO 2 | ||
33 | #endif | ||
34 | |||
35 | /* Return FD, unless FD would be a copy of standard input, output, or | ||
36 | error; in that case, return a duplicate of FD, closing FD. On | ||
37 | failure to duplicate, close FD, set errno, and return -1. Preserve | ||
38 | errno if FD is negative, so that the caller can always inspect | ||
39 | errno when the returned value is negative. | ||
40 | |||
41 | This function is usefully wrapped around functions that return file | ||
42 | descriptors, e.g., fd_safer (open ("file", O_RDONLY)). */ | ||
43 | |||
44 | int | ||
45 | fd_safer (int fd) | ||
46 | { | ||
47 | if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) | ||
48 | { | ||
49 | int f = dup_safer (fd); | ||
50 | int e = errno; | ||
51 | close (fd); | ||
52 | errno = e; | ||
53 | fd = f; | ||
54 | } | ||
55 | |||
56 | return fd; | ||
57 | } | ||
diff --git a/gl/fsusage.c b/gl/fsusage.c new file mode 100644 index 00000000..337bf531 --- /dev/null +++ b/gl/fsusage.c | |||
@@ -0,0 +1,264 @@ | |||
1 | /* fsusage.c -- return space usage of mounted file systems | ||
2 | |||
3 | Copyright (C) 1991, 1992, 1996, 1998, 1999, 2002, 2003, 2004, 2005, 2006 | ||
4 | Free Software Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | #include "fsusage.h" | ||
23 | |||
24 | #include <limits.h> | ||
25 | #include <sys/types.h> | ||
26 | |||
27 | #if STAT_STATVFS /* POSIX 1003.1-2001 (and later) with XSI */ | ||
28 | # include <sys/statvfs.h> | ||
29 | #else | ||
30 | /* Don't include backward-compatibility files unless they're needed. | ||
31 | Eventually we'd like to remove all this cruft. */ | ||
32 | # include <fcntl.h> | ||
33 | # include <unistd.h> | ||
34 | # include <sys/stat.h> | ||
35 | # if HAVE_SYS_PARAM_H | ||
36 | # include <sys/param.h> | ||
37 | # endif | ||
38 | # if HAVE_SYS_MOUNT_H | ||
39 | # include <sys/mount.h> | ||
40 | # endif | ||
41 | # if HAVE_SYS_VFS_H | ||
42 | # include <sys/vfs.h> | ||
43 | # endif | ||
44 | # if HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */ | ||
45 | # include <sys/fs/s5param.h> | ||
46 | # endif | ||
47 | # if defined HAVE_SYS_FILSYS_H && !defined _CRAY | ||
48 | # include <sys/filsys.h> /* SVR2 */ | ||
49 | # endif | ||
50 | # if HAVE_SYS_STATFS_H | ||
51 | # include <sys/statfs.h> | ||
52 | # endif | ||
53 | # if HAVE_DUSTAT_H /* AIX PS/2 */ | ||
54 | # include <sys/dustat.h> | ||
55 | # endif | ||
56 | # include "full-read.h" | ||
57 | #endif | ||
58 | |||
59 | /* The results of open() in this file are not used with fchdir, | ||
60 | therefore save some unnecessary work in fchdir.c. */ | ||
61 | #undef open | ||
62 | #undef close | ||
63 | |||
64 | /* Many space usage primitives use all 1 bits to denote a value that is | ||
65 | not applicable or unknown. Propagate this information by returning | ||
66 | a uintmax_t value that is all 1 bits if X is all 1 bits, even if X | ||
67 | is unsigned and narrower than uintmax_t. */ | ||
68 | #define PROPAGATE_ALL_ONES(x) \ | ||
69 | ((sizeof (x) < sizeof (uintmax_t) \ | ||
70 | && (~ (x) == (sizeof (x) < sizeof (int) \ | ||
71 | ? - (1 << (sizeof (x) * CHAR_BIT)) \ | ||
72 | : 0))) \ | ||
73 | ? UINTMAX_MAX : (uintmax_t) (x)) | ||
74 | |||
75 | /* Extract the top bit of X as an uintmax_t value. */ | ||
76 | #define EXTRACT_TOP_BIT(x) ((x) \ | ||
77 | & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1))) | ||
78 | |||
79 | /* If a value is negative, many space usage primitives store it into an | ||
80 | integer variable by assignment, even if the variable's type is unsigned. | ||
81 | So, if a space usage variable X's top bit is set, convert X to the | ||
82 | uintmax_t value V such that (- (uintmax_t) V) is the negative of | ||
83 | the original value. If X's top bit is clear, just yield X. | ||
84 | Use PROPAGATE_TOP_BIT if the original value might be negative; | ||
85 | otherwise, use PROPAGATE_ALL_ONES. */ | ||
86 | #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1)) | ||
87 | |||
88 | /* Fill in the fields of FSP with information about space usage for | ||
89 | the file system on which FILE resides. | ||
90 | DISK is the device on which FILE is mounted, for space-getting | ||
91 | methods that need to know it. | ||
92 | Return 0 if successful, -1 if not. When returning -1, ensure that | ||
93 | ERRNO is either a system error value, or zero if DISK is NULL | ||
94 | on a system that requires a non-NULL value. */ | ||
95 | int | ||
96 | get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp) | ||
97 | { | ||
98 | #if defined STAT_STATVFS /* POSIX */ | ||
99 | |||
100 | struct statvfs fsd; | ||
101 | |||
102 | if (statvfs (file, &fsd) < 0) | ||
103 | return -1; | ||
104 | |||
105 | /* f_frsize isn't guaranteed to be supported. */ | ||
106 | fsp->fsu_blocksize = (fsd.f_frsize | ||
107 | ? PROPAGATE_ALL_ONES (fsd.f_frsize) | ||
108 | : PROPAGATE_ALL_ONES (fsd.f_bsize)); | ||
109 | |||
110 | #elif defined STAT_STATFS2_FS_DATA /* Ultrix */ | ||
111 | |||
112 | struct fs_data fsd; | ||
113 | |||
114 | if (statfs (file, &fsd) != 1) | ||
115 | return -1; | ||
116 | |||
117 | fsp->fsu_blocksize = 1024; | ||
118 | fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot); | ||
119 | fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree); | ||
120 | fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen); | ||
121 | fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0; | ||
122 | fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot); | ||
123 | fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree); | ||
124 | |||
125 | #elif defined STAT_READ_FILSYS /* SVR2 */ | ||
126 | # ifndef SUPERBOFF | ||
127 | # define SUPERBOFF (SUPERB * 512) | ||
128 | # endif | ||
129 | |||
130 | struct filsys fsd; | ||
131 | int fd; | ||
132 | |||
133 | if (! disk) | ||
134 | { | ||
135 | errno = 0; | ||
136 | return -1; | ||
137 | } | ||
138 | |||
139 | fd = open (disk, O_RDONLY); | ||
140 | if (fd < 0) | ||
141 | return -1; | ||
142 | lseek (fd, (off_t) SUPERBOFF, 0); | ||
143 | if (full_read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd) | ||
144 | { | ||
145 | close (fd); | ||
146 | return -1; | ||
147 | } | ||
148 | close (fd); | ||
149 | |||
150 | fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512); | ||
151 | fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize); | ||
152 | fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree); | ||
153 | fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree); | ||
154 | fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0; | ||
155 | fsp->fsu_files = (fsd.s_isize == -1 | ||
156 | ? UINTMAX_MAX | ||
157 | : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1)); | ||
158 | fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode); | ||
159 | |||
160 | #elif defined STAT_STATFS3_OSF1 | ||
161 | |||
162 | struct statfs fsd; | ||
163 | |||
164 | if (statfs (file, &fsd, sizeof (struct statfs)) != 0) | ||
165 | return -1; | ||
166 | |||
167 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize); | ||
168 | |||
169 | #elif defined STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */ | ||
170 | |||
171 | struct statfs fsd; | ||
172 | |||
173 | if (statfs (file, &fsd) < 0) | ||
174 | return -1; | ||
175 | |||
176 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize); | ||
177 | |||
178 | # ifdef STATFS_TRUNCATES_BLOCK_COUNTS | ||
179 | |||
180 | /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the | ||
181 | struct statfs are truncated to 2GB. These conditions detect that | ||
182 | truncation, presumably without botching the 4.1.1 case, in which | ||
183 | the values are not truncated. The correct counts are stored in | ||
184 | undocumented spare fields. */ | ||
185 | if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0) | ||
186 | { | ||
187 | fsd.f_blocks = fsd.f_spare[0]; | ||
188 | fsd.f_bfree = fsd.f_spare[1]; | ||
189 | fsd.f_bavail = fsd.f_spare[2]; | ||
190 | } | ||
191 | # endif /* STATFS_TRUNCATES_BLOCK_COUNTS */ | ||
192 | |||
193 | #elif defined STAT_STATFS2_FSIZE /* 4.4BSD */ | ||
194 | |||
195 | struct statfs fsd; | ||
196 | |||
197 | if (statfs (file, &fsd) < 0) | ||
198 | return -1; | ||
199 | |||
200 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize); | ||
201 | |||
202 | #elif defined STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */ | ||
203 | |||
204 | # if !_AIX && !defined _SEQUENT_ && !defined DOLPHIN | ||
205 | # define f_bavail f_bfree | ||
206 | # endif | ||
207 | |||
208 | struct statfs fsd; | ||
209 | |||
210 | if (statfs (file, &fsd, sizeof fsd, 0) < 0) | ||
211 | return -1; | ||
212 | |||
213 | /* Empirically, the block counts on most SVR3 and SVR3-derived | ||
214 | systems seem to always be in terms of 512-byte blocks, | ||
215 | no matter what value f_bsize has. */ | ||
216 | # if _AIX || defined _CRAY | ||
217 | fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize); | ||
218 | # else | ||
219 | fsp->fsu_blocksize = 512; | ||
220 | # endif | ||
221 | |||
222 | #endif | ||
223 | |||
224 | #if (defined STAT_STATVFS \ | ||
225 | || (!defined STAT_STATFS2_FS_DATA && !defined STAT_READ_FILSYS)) | ||
226 | |||
227 | fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks); | ||
228 | fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree); | ||
229 | fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail); | ||
230 | fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0; | ||
231 | fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files); | ||
232 | fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree); | ||
233 | |||
234 | #endif | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | #if defined _AIX && defined _I386 | ||
240 | /* AIX PS/2 does not supply statfs. */ | ||
241 | |||
242 | int | ||
243 | statfs (char *file, struct statfs *fsb) | ||
244 | { | ||
245 | struct stat stats; | ||
246 | struct dustat fsd; | ||
247 | |||
248 | if (stat (file, &stats) != 0) | ||
249 | return -1; | ||
250 | if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd))) | ||
251 | return -1; | ||
252 | fsb->f_type = 0; | ||
253 | fsb->f_bsize = fsd.du_bsize; | ||
254 | fsb->f_blocks = fsd.du_fsize - fsd.du_isize; | ||
255 | fsb->f_bfree = fsd.du_tfree; | ||
256 | fsb->f_bavail = fsd.du_tfree; | ||
257 | fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb; | ||
258 | fsb->f_ffree = fsd.du_tinode; | ||
259 | fsb->f_fsid.val[0] = fsd.du_site; | ||
260 | fsb->f_fsid.val[1] = fsd.du_pckno; | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | #endif /* _AIX && _I386 */ | ||
diff --git a/gl/fsusage.h b/gl/fsusage.h new file mode 100644 index 00000000..7fa9f8d6 --- /dev/null +++ b/gl/fsusage.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* fsusage.h -- declarations for file system space usage info | ||
2 | |||
3 | Copyright (C) 1991, 1992, 1997, 2003, 2004, 2005, 2006 Free Software | ||
4 | Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | /* Space usage statistics for a file system. Blocks are 512-byte. */ | ||
21 | |||
22 | #if !defined FSUSAGE_H_ | ||
23 | # define FSUSAGE_H_ | ||
24 | |||
25 | # include <stdint.h> | ||
26 | # include <stdbool.h> | ||
27 | |||
28 | struct fs_usage | ||
29 | { | ||
30 | uintmax_t fsu_blocksize; /* Size of a block. */ | ||
31 | uintmax_t fsu_blocks; /* Total blocks. */ | ||
32 | uintmax_t fsu_bfree; /* Free blocks available to superuser. */ | ||
33 | uintmax_t fsu_bavail; /* Free blocks available to non-superuser. */ | ||
34 | bool fsu_bavail_top_bit_set; /* 1 if fsu_bavail represents a value < 0. */ | ||
35 | uintmax_t fsu_files; /* Total file nodes. */ | ||
36 | uintmax_t fsu_ffree; /* Free file nodes. */ | ||
37 | }; | ||
38 | |||
39 | int get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp); | ||
40 | |||
41 | #endif | ||
diff --git a/gl/full-read.c b/gl/full-read.c new file mode 100644 index 00000000..8c3472a4 --- /dev/null +++ b/gl/full-read.c | |||
@@ -0,0 +1,19 @@ | |||
1 | /* An interface to read that retries after partial reads and interrupts. | ||
2 | Copyright (C) 2002, 2003 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #define FULL_READ | ||
19 | #include "full-write.c" | ||
diff --git a/gl/full-read.h b/gl/full-read.h new file mode 100644 index 00000000..05d83a76 --- /dev/null +++ b/gl/full-read.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* An interface to read() that reads all it is asked to read. | ||
2 | |||
3 | Copyright (C) 2002 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, read to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #include <stddef.h> | ||
20 | |||
21 | /* Read COUNT bytes at BUF to descriptor FD, retrying if interrupted | ||
22 | or if partial reads occur. Return the number of bytes successfully | ||
23 | read, setting errno if that is less than COUNT. errno = 0 means EOF. */ | ||
24 | extern size_t full_read (int fd, void *buf, size_t count); | ||
diff --git a/gl/full-write.c b/gl/full-write.c new file mode 100644 index 00000000..cc168720 --- /dev/null +++ b/gl/full-write.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* An interface to read and write that retries (if necessary) until complete. | ||
2 | |||
3 | Copyright (C) 1993, 1994, 1997, 1998, 1999, 2000, 2001, 2002, 2003, | ||
4 | 2004, 2005, 2006 Free Software Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | /* Specification. */ | ||
23 | #ifdef FULL_READ | ||
24 | # include "full-read.h" | ||
25 | #else | ||
26 | # include "full-write.h" | ||
27 | #endif | ||
28 | |||
29 | #include <errno.h> | ||
30 | |||
31 | #ifdef FULL_READ | ||
32 | # include "safe-read.h" | ||
33 | # define safe_rw safe_read | ||
34 | # define full_rw full_read | ||
35 | # undef const | ||
36 | # define const /* empty */ | ||
37 | #else | ||
38 | # include "safe-write.h" | ||
39 | # define safe_rw safe_write | ||
40 | # define full_rw full_write | ||
41 | #endif | ||
42 | |||
43 | #ifdef FULL_READ | ||
44 | /* Set errno to zero upon EOF. */ | ||
45 | # define ZERO_BYTE_TRANSFER_ERRNO 0 | ||
46 | #else | ||
47 | /* Some buggy drivers return 0 when one tries to write beyond | ||
48 | a device's end. (Example: Linux 1.2.13 on /dev/fd0.) | ||
49 | Set errno to ENOSPC so they get a sensible diagnostic. */ | ||
50 | # define ZERO_BYTE_TRANSFER_ERRNO ENOSPC | ||
51 | #endif | ||
52 | |||
53 | /* Write(read) COUNT bytes at BUF to(from) descriptor FD, retrying if | ||
54 | interrupted or if a partial write(read) occurs. Return the number | ||
55 | of bytes transferred. | ||
56 | When writing, set errno if fewer than COUNT bytes are written. | ||
57 | When reading, if fewer than COUNT bytes are read, you must examine | ||
58 | errno to distinguish failure from EOF (errno == 0). */ | ||
59 | size_t | ||
60 | full_rw (int fd, const void *buf, size_t count) | ||
61 | { | ||
62 | size_t total = 0; | ||
63 | const char *ptr = (const char *) buf; | ||
64 | |||
65 | while (count > 0) | ||
66 | { | ||
67 | size_t n_rw = safe_rw (fd, ptr, count); | ||
68 | if (n_rw == (size_t) -1) | ||
69 | break; | ||
70 | if (n_rw == 0) | ||
71 | { | ||
72 | errno = ZERO_BYTE_TRANSFER_ERRNO; | ||
73 | break; | ||
74 | } | ||
75 | total += n_rw; | ||
76 | ptr += n_rw; | ||
77 | count -= n_rw; | ||
78 | } | ||
79 | |||
80 | return total; | ||
81 | } | ||
diff --git a/gl/full-write.h b/gl/full-write.h new file mode 100644 index 00000000..d20d2fe4 --- /dev/null +++ b/gl/full-write.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* An interface to write() that writes all it is asked to write. | ||
2 | |||
3 | Copyright (C) 2002-2003 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #include <stddef.h> | ||
20 | |||
21 | |||
22 | #ifdef __cplusplus | ||
23 | extern "C" { | ||
24 | #endif | ||
25 | |||
26 | |||
27 | /* Write COUNT bytes at BUF to descriptor FD, retrying if interrupted | ||
28 | or if partial writes occur. Return the number of bytes successfully | ||
29 | written, setting errno if that is less than COUNT. */ | ||
30 | extern size_t full_write (int fd, const void *buf, size_t count); | ||
31 | |||
32 | |||
33 | #ifdef __cplusplus | ||
34 | } | ||
35 | #endif | ||
diff --git a/gl/gai_strerror.c b/gl/gai_strerror.c new file mode 100644 index 00000000..7f0e034e --- /dev/null +++ b/gl/gai_strerror.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* Copyright (C) 1997, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. | ||
2 | This file is part of the GNU C Library. | ||
3 | Contributed by Philip Blundell <pjb27@cam.ac.uk>, 1997. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #ifndef _LIBC | ||
20 | # include <config.h> | ||
21 | # include "getaddrinfo.h" | ||
22 | #endif | ||
23 | |||
24 | #include <stdio.h> | ||
25 | #ifdef HAVE_NETDB_H | ||
26 | # include <netdb.h> | ||
27 | #endif | ||
28 | |||
29 | #ifdef _LIBC | ||
30 | # include <libintl.h> | ||
31 | #else | ||
32 | # include "gettext.h" | ||
33 | # define _(String) gettext (String) | ||
34 | # define N_(String) String | ||
35 | #endif | ||
36 | |||
37 | static struct | ||
38 | { | ||
39 | int code; | ||
40 | const char *msg; | ||
41 | } | ||
42 | values[] = | ||
43 | { | ||
44 | { EAI_ADDRFAMILY, N_("Address family for hostname not supported") }, | ||
45 | { EAI_AGAIN, N_("Temporary failure in name resolution") }, | ||
46 | { EAI_BADFLAGS, N_("Bad value for ai_flags") }, | ||
47 | { EAI_FAIL, N_("Non-recoverable failure in name resolution") }, | ||
48 | { EAI_FAMILY, N_("ai_family not supported") }, | ||
49 | { EAI_MEMORY, N_("Memory allocation failure") }, | ||
50 | { EAI_NODATA, N_("No address associated with hostname") }, | ||
51 | { EAI_NONAME, N_("Name or service not known") }, | ||
52 | { EAI_SERVICE, N_("Servname not supported for ai_socktype") }, | ||
53 | { EAI_SOCKTYPE, N_("ai_socktype not supported") }, | ||
54 | { EAI_SYSTEM, N_("System error") }, | ||
55 | #ifdef __USE_GNU | ||
56 | { EAI_INPROGRESS, N_("Processing request in progress") }, | ||
57 | { EAI_CANCELED, N_("Request canceled") }, | ||
58 | { EAI_NOTCANCELED, N_("Request not canceled") }, | ||
59 | { EAI_ALLDONE, N_("All requests done") }, | ||
60 | { EAI_INTR, N_("Interrupted by a signal") }, | ||
61 | { EAI_IDN_ENCODE, N_("Parameter string not correctly encoded") } | ||
62 | #endif | ||
63 | }; | ||
64 | |||
65 | const char * | ||
66 | gai_strerror (int code) | ||
67 | { | ||
68 | size_t i; | ||
69 | for (i = 0; i < sizeof (values) / sizeof (values[0]); ++i) | ||
70 | if (values[i].code == code) | ||
71 | return _(values[i].msg); | ||
72 | |||
73 | return _("Unknown error"); | ||
74 | } | ||
75 | #ifdef _LIBC | ||
76 | libc_hidden_def (gai_strerror) | ||
77 | #endif | ||
diff --git a/gl/getaddrinfo.c b/gl/getaddrinfo.c new file mode 100644 index 00000000..f523f765 --- /dev/null +++ b/gl/getaddrinfo.c | |||
@@ -0,0 +1,417 @@ | |||
1 | /* Get address information (partial implementation). | ||
2 | Copyright (C) 1997, 2001, 2002, 2004, 2005, 2006 Free Software | ||
3 | Foundation, Inc. | ||
4 | Contributed by Simon Josefsson <simon@josefsson.org>. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | #include "getaddrinfo.h" | ||
23 | |||
24 | #if HAVE_NETINET_IN_H | ||
25 | # include <netinet/in.h> | ||
26 | #endif | ||
27 | |||
28 | /* Get calloc. */ | ||
29 | #include <stdlib.h> | ||
30 | |||
31 | /* Get memcpy. */ | ||
32 | #include <string.h> | ||
33 | |||
34 | #include <stdbool.h> | ||
35 | |||
36 | #include "gettext.h" | ||
37 | #define _(String) gettext (String) | ||
38 | #define N_(String) String | ||
39 | |||
40 | #include "inet_ntop.h" | ||
41 | #include "snprintf.h" | ||
42 | #include "strdup.h" | ||
43 | |||
44 | /* BeOS has AF_INET, but not PF_INET. */ | ||
45 | #ifndef PF_INET | ||
46 | # define PF_INET AF_INET | ||
47 | #endif | ||
48 | /* BeOS also lacks PF_UNSPEC. */ | ||
49 | #ifndef PF_UNSPEC | ||
50 | # define PF_UNSPEC 0 | ||
51 | #endif | ||
52 | |||
53 | #if defined _WIN32 || defined __WIN32__ | ||
54 | # define WIN32_NATIVE | ||
55 | #endif | ||
56 | |||
57 | #ifdef WIN32_NATIVE | ||
58 | typedef int (WSAAPI *getaddrinfo_func) (const char*, const char*, | ||
59 | const struct addrinfo*, | ||
60 | struct addrinfo**); | ||
61 | typedef void (WSAAPI *freeaddrinfo_func) (struct addrinfo*); | ||
62 | typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr*, | ||
63 | socklen_t, char*, DWORD, | ||
64 | char*, DWORD, int); | ||
65 | |||
66 | static getaddrinfo_func getaddrinfo_ptr = NULL; | ||
67 | static freeaddrinfo_func freeaddrinfo_ptr = NULL; | ||
68 | static getnameinfo_func getnameinfo_ptr = NULL; | ||
69 | |||
70 | static int | ||
71 | use_win32_p (void) | ||
72 | { | ||
73 | static int done = 0; | ||
74 | HMODULE h; | ||
75 | |||
76 | if (done) | ||
77 | return getaddrinfo_ptr ? 1 : 0; | ||
78 | |||
79 | done = 1; | ||
80 | |||
81 | h = GetModuleHandle ("ws2_32.dll"); | ||
82 | |||
83 | if (h) | ||
84 | { | ||
85 | getaddrinfo_ptr = (getaddrinfo_func) GetProcAddress (h, "getaddrinfo"); | ||
86 | freeaddrinfo_ptr = (freeaddrinfo_func) GetProcAddress (h, "freeaddrinfo"); | ||
87 | getnameinfo_ptr = (getnameinfo_func) GetProcAddress (h, "getnameinfo"); | ||
88 | } | ||
89 | |||
90 | /* If either is missing, something is odd. */ | ||
91 | if (!getaddrinfo_ptr || !freeaddrinfo_ptr || !getnameinfo_ptr) | ||
92 | { | ||
93 | getaddrinfo_ptr = NULL; | ||
94 | freeaddrinfo_ptr = NULL; | ||
95 | getnameinfo_ptr = NULL; | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | return 1; | ||
100 | } | ||
101 | #endif | ||
102 | |||
103 | static inline bool | ||
104 | validate_family (int family) | ||
105 | { | ||
106 | /* FIXME: Support more families. */ | ||
107 | #if HAVE_IPV4 | ||
108 | if (family == PF_INET) | ||
109 | return true; | ||
110 | #endif | ||
111 | #if HAVE_IPV6 | ||
112 | if (family == PF_INET6) | ||
113 | return true; | ||
114 | #endif | ||
115 | if (family == PF_UNSPEC) | ||
116 | return true; | ||
117 | return false; | ||
118 | } | ||
119 | |||
120 | /* Translate name of a service location and/or a service name to set of | ||
121 | socket addresses. */ | ||
122 | int | ||
123 | getaddrinfo (const char *restrict nodename, | ||
124 | const char *restrict servname, | ||
125 | const struct addrinfo *restrict hints, | ||
126 | struct addrinfo **restrict res) | ||
127 | { | ||
128 | struct addrinfo *tmp; | ||
129 | int port = 0; | ||
130 | struct hostent *he; | ||
131 | void *storage; | ||
132 | size_t size; | ||
133 | #if HAVE_IPV6 | ||
134 | struct v6_pair { | ||
135 | struct addrinfo addrinfo; | ||
136 | struct sockaddr_in6 sockaddr_in6; | ||
137 | }; | ||
138 | #endif | ||
139 | #if HAVE_IPV4 | ||
140 | struct v4_pair { | ||
141 | struct addrinfo addrinfo; | ||
142 | struct sockaddr_in sockaddr_in; | ||
143 | }; | ||
144 | #endif | ||
145 | |||
146 | #ifdef WIN32_NATIVE | ||
147 | if (use_win32_p ()) | ||
148 | return getaddrinfo_ptr (nodename, servname, hints, res); | ||
149 | #endif | ||
150 | |||
151 | if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE))) | ||
152 | /* FIXME: Support more flags. */ | ||
153 | return EAI_BADFLAGS; | ||
154 | |||
155 | if (hints && !validate_family (hints->ai_family)) | ||
156 | return EAI_FAMILY; | ||
157 | |||
158 | if (hints && | ||
159 | hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM) | ||
160 | /* FIXME: Support other socktype. */ | ||
161 | return EAI_SOCKTYPE; /* FIXME: Better return code? */ | ||
162 | |||
163 | if (!nodename) | ||
164 | { | ||
165 | if (!(hints->ai_flags & AI_PASSIVE)) | ||
166 | return EAI_NONAME; | ||
167 | |||
168 | #ifdef HAVE_IPV6 | ||
169 | nodename = (hints->ai_family == AF_INET6) ? "::" : "0.0.0.0"; | ||
170 | #else | ||
171 | nodename = "0.0.0.0"; | ||
172 | #endif | ||
173 | } | ||
174 | |||
175 | if (servname) | ||
176 | { | ||
177 | struct servent *se = NULL; | ||
178 | const char *proto = | ||
179 | (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp"; | ||
180 | |||
181 | if (!(hints->ai_flags & AI_NUMERICSERV)) | ||
182 | /* FIXME: Use getservbyname_r if available. */ | ||
183 | se = getservbyname (servname, proto); | ||
184 | |||
185 | if (!se) | ||
186 | { | ||
187 | char *c; | ||
188 | if (!(*servname >= '0' && *servname <= '9')) | ||
189 | return EAI_NONAME; | ||
190 | port = strtoul (servname, &c, 10); | ||
191 | if (*c || port > 0xffff) | ||
192 | return EAI_NONAME; | ||
193 | port = htons (port); | ||
194 | } | ||
195 | else | ||
196 | port = se->s_port; | ||
197 | } | ||
198 | |||
199 | /* FIXME: Use gethostbyname_r if available. */ | ||
200 | he = gethostbyname (nodename); | ||
201 | if (!he || he->h_addr_list[0] == NULL) | ||
202 | return EAI_NONAME; | ||
203 | |||
204 | switch (he->h_addrtype) | ||
205 | { | ||
206 | #if HAVE_IPV6 | ||
207 | case PF_INET6: | ||
208 | size = sizeof (struct v6_pair); | ||
209 | break; | ||
210 | #endif | ||
211 | |||
212 | #if HAVE_IPV4 | ||
213 | case PF_INET: | ||
214 | size = sizeof (struct v4_pair); | ||
215 | break; | ||
216 | #endif | ||
217 | |||
218 | default: | ||
219 | return EAI_NODATA; | ||
220 | } | ||
221 | |||
222 | storage = calloc (1, size); | ||
223 | if (!storage) | ||
224 | return EAI_MEMORY; | ||
225 | |||
226 | switch (he->h_addrtype) | ||
227 | { | ||
228 | #if HAVE_IPV6 | ||
229 | case PF_INET6: | ||
230 | { | ||
231 | struct v6_pair *p = storage; | ||
232 | struct sockaddr_in6 *sinp = &p->sockaddr_in6; | ||
233 | tmp = &p->addrinfo; | ||
234 | |||
235 | if (port) | ||
236 | sinp->sin6_port = port; | ||
237 | |||
238 | if (he->h_length != sizeof (sinp->sin6_addr)) | ||
239 | { | ||
240 | free (storage); | ||
241 | return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */ | ||
242 | } | ||
243 | |||
244 | memcpy (&sinp->sin6_addr, he->h_addr_list[0], sizeof sinp->sin6_addr); | ||
245 | |||
246 | tmp->ai_addr = (struct sockaddr *) sinp; | ||
247 | tmp->ai_addrlen = sizeof *sinp; | ||
248 | } | ||
249 | break; | ||
250 | #endif | ||
251 | |||
252 | #if HAVE_IPV4 | ||
253 | case PF_INET: | ||
254 | { | ||
255 | struct v4_pair *p = storage; | ||
256 | struct sockaddr_in *sinp = &p->sockaddr_in; | ||
257 | tmp = &p->addrinfo; | ||
258 | |||
259 | if (port) | ||
260 | sinp->sin_port = port; | ||
261 | |||
262 | if (he->h_length != sizeof (sinp->sin_addr)) | ||
263 | { | ||
264 | free (storage); | ||
265 | return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */ | ||
266 | } | ||
267 | |||
268 | memcpy (&sinp->sin_addr, he->h_addr_list[0], sizeof sinp->sin_addr); | ||
269 | |||
270 | tmp->ai_addr = (struct sockaddr *) sinp; | ||
271 | tmp->ai_addrlen = sizeof *sinp; | ||
272 | } | ||
273 | break; | ||
274 | #endif | ||
275 | |||
276 | default: | ||
277 | free (storage); | ||
278 | return EAI_NODATA; | ||
279 | } | ||
280 | |||
281 | if (hints && hints->ai_flags & AI_CANONNAME) | ||
282 | { | ||
283 | const char *cn; | ||
284 | if (he->h_name) | ||
285 | cn = he->h_name; | ||
286 | else | ||
287 | cn = nodename; | ||
288 | |||
289 | tmp->ai_canonname = strdup (cn); | ||
290 | if (!tmp->ai_canonname) | ||
291 | { | ||
292 | free (storage); | ||
293 | return EAI_MEMORY; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | tmp->ai_protocol = (hints) ? hints->ai_protocol : 0; | ||
298 | tmp->ai_socktype = (hints) ? hints->ai_socktype : 0; | ||
299 | tmp->ai_addr->sa_family = he->h_addrtype; | ||
300 | tmp->ai_family = he->h_addrtype; | ||
301 | |||
302 | /* FIXME: If more than one address, create linked list of addrinfo's. */ | ||
303 | |||
304 | *res = tmp; | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | /* Free `addrinfo' structure AI including associated storage. */ | ||
310 | void | ||
311 | freeaddrinfo (struct addrinfo *ai) | ||
312 | { | ||
313 | #ifdef WIN32_NATIVE | ||
314 | if (use_win32_p ()) | ||
315 | { | ||
316 | freeaddrinfo_ptr (ai); | ||
317 | return; | ||
318 | } | ||
319 | #endif | ||
320 | |||
321 | while (ai) | ||
322 | { | ||
323 | struct addrinfo *cur; | ||
324 | |||
325 | cur = ai; | ||
326 | ai = ai->ai_next; | ||
327 | |||
328 | if (cur->ai_canonname) free (cur->ai_canonname); | ||
329 | free (cur); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, | ||
334 | char *restrict node, socklen_t nodelen, | ||
335 | char *restrict service, socklen_t servicelen, | ||
336 | int flags) | ||
337 | { | ||
338 | #ifdef WIN32_NATIVE | ||
339 | if (use_win32_p ()) | ||
340 | return getnameinfo_ptr (sa, salen, node, nodelen, | ||
341 | service, servicelen, flags); | ||
342 | #endif | ||
343 | |||
344 | /* FIXME: Support other flags. */ | ||
345 | if ((node && nodelen > 0 && !(flags & NI_NUMERICHOST)) || | ||
346 | (service && servicelen > 0 && !(flags & NI_NUMERICHOST)) || | ||
347 | (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV))) | ||
348 | return EAI_BADFLAGS; | ||
349 | |||
350 | if (sa == NULL || salen < sizeof (sa->sa_family)) | ||
351 | return EAI_FAMILY; | ||
352 | |||
353 | switch (sa->sa_family) | ||
354 | { | ||
355 | #if HAVE_IPV4 | ||
356 | case AF_INET: | ||
357 | if (salen < sizeof (struct sockaddr_in)) | ||
358 | return EAI_FAMILY; | ||
359 | break; | ||
360 | #endif | ||
361 | #if HAVE_IPV6 | ||
362 | case AF_INET6: | ||
363 | if (salen < sizeof (struct sockaddr_in6)) | ||
364 | return EAI_FAMILY; | ||
365 | break; | ||
366 | #endif | ||
367 | default: | ||
368 | return EAI_FAMILY; | ||
369 | } | ||
370 | |||
371 | if (node && nodelen > 0 && flags & NI_NUMERICHOST) | ||
372 | { | ||
373 | switch (sa->sa_family) | ||
374 | { | ||
375 | #if HAVE_IPV4 | ||
376 | case AF_INET: | ||
377 | if (!inet_ntop (AF_INET, | ||
378 | &(((const struct sockaddr_in *) sa)->sin_addr), | ||
379 | node, nodelen)) | ||
380 | return EAI_SYSTEM; | ||
381 | break; | ||
382 | #endif | ||
383 | |||
384 | #if HAVE_IPV6 | ||
385 | case AF_INET6: | ||
386 | if (!inet_ntop (AF_INET6, | ||
387 | &(((const struct sockaddr_in6 *) sa)->sin6_addr), | ||
388 | node, nodelen)) | ||
389 | return EAI_SYSTEM; | ||
390 | break; | ||
391 | #endif | ||
392 | |||
393 | default: | ||
394 | return EAI_FAMILY; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | if (service && servicelen > 0 && flags & NI_NUMERICSERV) | ||
399 | switch (sa->sa_family) | ||
400 | { | ||
401 | #if HAVE_IPV4 | ||
402 | case AF_INET: | ||
403 | #endif | ||
404 | #if HAVE_IPV6 | ||
405 | case AF_INET6: | ||
406 | #endif | ||
407 | { | ||
408 | unsigned short int port | ||
409 | = ntohs (((const struct sockaddr_in *) sa)->sin_port); | ||
410 | if (servicelen <= snprintf (service, servicelen, "%u", port)) | ||
411 | return EAI_OVERFLOW; | ||
412 | } | ||
413 | break; | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | } | ||
diff --git a/gl/getaddrinfo.h b/gl/getaddrinfo.h new file mode 100644 index 00000000..b4ef242c --- /dev/null +++ b/gl/getaddrinfo.h | |||
@@ -0,0 +1,155 @@ | |||
1 | /* Get address information. | ||
2 | Copyright (C) 1996-2002, 2003, 2004, 2005, 2006 | ||
3 | Free Software Foundation, Inc. | ||
4 | Contributed by Simon Josefsson <simon@josefsson.org>. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #ifndef GETADDRINFO_H | ||
21 | #define GETADDRINFO_H | ||
22 | |||
23 | /* sys/socket.h in i386-unknown-freebsd4.10 and | ||
24 | powerpc-apple-darwin5.5 require sys/types.h, so include it first. | ||
25 | Then we'll also get 'socklen_t' and 'struct sockaddr' which are | ||
26 | used below. */ | ||
27 | #include <sys/types.h> | ||
28 | /* Get all getaddrinfo related declarations, if available. */ | ||
29 | #include <sys/socket.h> | ||
30 | #ifdef HAVE_NETDB_H | ||
31 | # include <netdb.h> | ||
32 | #endif | ||
33 | |||
34 | #ifndef HAVE_STRUCT_ADDRINFO | ||
35 | |||
36 | /* Structure to contain information about address of a service provider. */ | ||
37 | struct addrinfo | ||
38 | { | ||
39 | int ai_flags; /* Input flags. */ | ||
40 | int ai_family; /* Protocol family for socket. */ | ||
41 | int ai_socktype; /* Socket type. */ | ||
42 | int ai_protocol; /* Protocol for socket. */ | ||
43 | socklen_t ai_addrlen; /* Length of socket address. */ | ||
44 | struct sockaddr *ai_addr; /* Socket address for socket. */ | ||
45 | char *ai_canonname; /* Canonical name for service location. */ | ||
46 | struct addrinfo *ai_next; /* Pointer to next in list. */ | ||
47 | }; | ||
48 | #endif | ||
49 | |||
50 | /* Possible values for `ai_flags' field in `addrinfo' structure. */ | ||
51 | #ifndef AI_PASSIVE | ||
52 | # define AI_PASSIVE 0x0001 /* Socket address is intended for `bind'. */ | ||
53 | #endif | ||
54 | #ifndef AI_CANONNAME | ||
55 | # define AI_CANONNAME 0x0002 /* Request for canonical name. */ | ||
56 | #endif | ||
57 | #ifndef AI_NUMERICSERV | ||
58 | # define AI_NUMERICSERV 0x0400 /* Don't use name resolution. */ | ||
59 | #endif | ||
60 | |||
61 | #if 0 | ||
62 | /* The commented out definitions below are not yet implemented in the | ||
63 | GNULIB getaddrinfo() replacement, so are not yet needed and may, in fact, | ||
64 | cause conflicts on systems with a getaddrinfo() function which does not | ||
65 | define them. | ||
66 | |||
67 | If they are restored, be sure to protect the definitions with #ifndef. */ | ||
68 | #define AI_NUMERICHOST 0x0004 /* Don't use name resolution. */ | ||
69 | #define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */ | ||
70 | #define AI_ALL 0x0010 /* Return IPv4 mapped and IPv6 addresses. */ | ||
71 | #define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose | ||
72 | returned address type.. */ | ||
73 | #endif /* 0 */ | ||
74 | |||
75 | /* Error values for `getaddrinfo' function. */ | ||
76 | #ifndef EAI_BADFLAGS | ||
77 | # define EAI_BADFLAGS -1 /* Invalid value for `ai_flags' field. */ | ||
78 | # define EAI_NONAME -2 /* NAME or SERVICE is unknown. */ | ||
79 | # define EAI_AGAIN -3 /* Temporary failure in name resolution. */ | ||
80 | # define EAI_FAIL -4 /* Non-recoverable failure in name res. */ | ||
81 | # define EAI_NODATA -5 /* No address associated with NAME. */ | ||
82 | # define EAI_FAMILY -6 /* `ai_family' not supported. */ | ||
83 | # define EAI_SOCKTYPE -7 /* `ai_socktype' not supported. */ | ||
84 | # define EAI_SERVICE -8 /* SERVICE not supported for `ai_socktype'. */ | ||
85 | # define EAI_MEMORY -10 /* Memory allocation failure. */ | ||
86 | #endif | ||
87 | #ifndef EAI_OVERFLOW | ||
88 | /* Not defined on mingw32. */ | ||
89 | # define EAI_OVERFLOW -12 /* Argument buffer overflow. */ | ||
90 | #endif | ||
91 | #ifndef EAI_ADDRFAMILY | ||
92 | /* Not defined on mingw32. */ | ||
93 | # define EAI_ADDRFAMILY -9 /* Address family for NAME not supported. */ | ||
94 | #endif | ||
95 | #ifndef EAI_SYSTEM | ||
96 | /* Not defined on mingw32. */ | ||
97 | # define EAI_SYSTEM -11 /* System error returned in `errno'. */ | ||
98 | #endif | ||
99 | |||
100 | #ifdef __USE_GNU | ||
101 | # ifndef EAI_INPROGRESS | ||
102 | # define EAI_INPROGRESS -100 /* Processing request in progress. */ | ||
103 | # define EAI_CANCELED -101 /* Request canceled. */ | ||
104 | # define EAI_NOTCANCELED -102 /* Request not canceled. */ | ||
105 | # define EAI_ALLDONE -103 /* All requests done. */ | ||
106 | # define EAI_INTR -104 /* Interrupted by a signal. */ | ||
107 | # define EAI_IDN_ENCODE -105 /* IDN encoding failed. */ | ||
108 | # endif | ||
109 | #endif | ||
110 | |||
111 | #if !HAVE_DECL_GETADDRINFO | ||
112 | /* Translate name of a service location and/or a service name to set of | ||
113 | socket addresses. | ||
114 | For more details, see the POSIX:2001 specification | ||
115 | <http://www.opengroup.org/susv3xsh/getaddrinfo.html>. */ | ||
116 | extern int getaddrinfo (const char *restrict nodename, | ||
117 | const char *restrict servname, | ||
118 | const struct addrinfo *restrict hints, | ||
119 | struct addrinfo **restrict res); | ||
120 | #endif | ||
121 | |||
122 | #if !HAVE_DECL_FREEADDRINFO | ||
123 | /* Free `addrinfo' structure AI including associated storage. | ||
124 | For more details, see the POSIX:2001 specification | ||
125 | <http://www.opengroup.org/susv3xsh/getaddrinfo.html>. */ | ||
126 | extern void freeaddrinfo (struct addrinfo *ai); | ||
127 | #endif | ||
128 | |||
129 | #if !HAVE_DECL_GAI_STRERROR | ||
130 | /* Convert error return from getaddrinfo() to a string. | ||
131 | For more details, see the POSIX:2001 specification | ||
132 | <http://www.opengroup.org/susv3xsh/gai_strerror.html>. */ | ||
133 | extern const char *gai_strerror (int ecode); | ||
134 | #endif | ||
135 | |||
136 | #if !HAVE_DECL_GETNAMEINFO | ||
137 | /* Convert socket address to printable node and service names. | ||
138 | For more details, see the POSIX:2001 specification | ||
139 | <http://www.opengroup.org/susv3xsh/getnameinfo.html>. */ | ||
140 | extern int getnameinfo(const struct sockaddr *restrict sa, socklen_t salen, | ||
141 | char *restrict node, socklen_t nodelen, | ||
142 | char *restrict service, socklen_t servicelen, | ||
143 | int flags); | ||
144 | |||
145 | #endif | ||
146 | |||
147 | /* Possible flags for getnameinfo. */ | ||
148 | #ifndef NI_NUMERICHOST | ||
149 | # define NI_NUMERICHOST 1 | ||
150 | #endif | ||
151 | #ifndef NI_NUMERICSERV | ||
152 | # define NI_NUMERICSERV 2 | ||
153 | #endif | ||
154 | |||
155 | #endif /* GETADDRINFO_H */ | ||
diff --git a/gl/gethostname.c b/gl/gethostname.c new file mode 100644 index 00000000..eedc40ec --- /dev/null +++ b/gl/gethostname.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* gethostname emulation for SysV and POSIX.1. | ||
2 | |||
3 | Copyright (C) 1992, 2003, 2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* David MacKenzie <djm@gnu.ai.mit.edu> */ | ||
20 | |||
21 | #include <config.h> | ||
22 | |||
23 | #ifdef HAVE_UNAME | ||
24 | # include <sys/utsname.h> | ||
25 | #endif | ||
26 | |||
27 | /* Put up to LEN chars of the host name into NAME. | ||
28 | Null terminate it if the name is shorter than LEN. | ||
29 | Return 0 if ok, -1 if error. */ | ||
30 | |||
31 | #include <stddef.h> | ||
32 | |||
33 | int | ||
34 | gethostname (char *name, size_t len) | ||
35 | { | ||
36 | #ifdef HAVE_UNAME | ||
37 | struct utsname uts; | ||
38 | |||
39 | if (uname (&uts) == -1) | ||
40 | return -1; | ||
41 | if (len > sizeof (uts.nodename)) | ||
42 | { | ||
43 | /* More space than we need is available. */ | ||
44 | name[sizeof (uts.nodename)] = '\0'; | ||
45 | len = sizeof (uts.nodename); | ||
46 | } | ||
47 | strncpy (name, uts.nodename, len); | ||
48 | #else | ||
49 | strcpy (name, ""); /* Hardcode your system name if you want. */ | ||
50 | #endif | ||
51 | return 0; | ||
52 | } | ||
diff --git a/gl/getloadavg.c b/gl/getloadavg.c new file mode 100644 index 00000000..cfa62735 --- /dev/null +++ b/gl/getloadavg.c | |||
@@ -0,0 +1,1020 @@ | |||
1 | /* Get the system load averages. | ||
2 | |||
3 | Copyright (C) 1985, 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994, | ||
4 | 1995, 1997, 1999, 2000, 2003, 2004, 2005, 2006 Free Software | ||
5 | Foundation, Inc. | ||
6 | |||
7 | NOTE: The canonical source of this file is maintained with gnulib. | ||
8 | Bugs can be reported to bug-gnulib@gnu.org. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2, or (at your option) | ||
13 | any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | ||
23 | USA. */ | ||
24 | |||
25 | /* Compile-time symbols that this file uses: | ||
26 | |||
27 | HAVE_PSTAT_GETDYNAMIC Define this if your system has the | ||
28 | pstat_getdynamic function. I think it | ||
29 | is unique to HPUX9. The best way to get the | ||
30 | definition is through the AC_FUNC_GETLOADAVG | ||
31 | macro that comes with autoconf 2.13 or newer. | ||
32 | If that isn't an option, then just put | ||
33 | AC_CHECK_FUNCS(pstat_getdynamic) in your | ||
34 | configure.in file. | ||
35 | FIXUP_KERNEL_SYMBOL_ADDR() Adjust address in returned struct nlist. | ||
36 | KERNEL_FILE Name of the kernel file to nlist. | ||
37 | LDAV_CVT() Scale the load average from the kernel. | ||
38 | Returns a double. | ||
39 | LDAV_SYMBOL Name of kernel symbol giving load average. | ||
40 | LOAD_AVE_TYPE Type of the load average array in the kernel. | ||
41 | Must be defined unless one of | ||
42 | apollo, DGUX, NeXT, or UMAX is defined; | ||
43 | or we have libkstat; | ||
44 | otherwise, no load average is available. | ||
45 | HAVE_NLIST_H nlist.h is available. NLIST_STRUCT defaults | ||
46 | to this. | ||
47 | NLIST_STRUCT Include nlist.h, not a.out.h, and | ||
48 | the nlist n_name element is a pointer, | ||
49 | not an array. | ||
50 | HAVE_STRUCT_NLIST_N_UN_N_NAME `n_un.n_name' is member of `struct nlist'. | ||
51 | LINUX_LDAV_FILE [__linux__, __CYGWIN__]: File containing | ||
52 | load averages. | ||
53 | |||
54 | Specific system predefines this file uses, aside from setting | ||
55 | default values if not emacs: | ||
56 | |||
57 | apollo | ||
58 | BSD Real BSD, not just BSD-like. | ||
59 | convex | ||
60 | DGUX | ||
61 | eunice UNIX emulator under VMS. | ||
62 | hpux | ||
63 | __MSDOS__ No-op for MSDOS. | ||
64 | NeXT | ||
65 | sgi | ||
66 | sequent Sequent Dynix 3.x.x (BSD) | ||
67 | _SEQUENT_ Sequent DYNIX/ptx 1.x.x (SYSV) | ||
68 | sony_news NEWS-OS (works at least for 4.1C) | ||
69 | UMAX | ||
70 | UMAX4_3 | ||
71 | VMS | ||
72 | WINDOWS32 No-op for Windows95/NT. | ||
73 | __linux__ Linux: assumes /proc file system mounted. | ||
74 | Support from Michael K. Johnson. | ||
75 | __CYGWIN__ Cygwin emulates linux /proc/loadavg. | ||
76 | __NetBSD__ NetBSD: assumes /kern file system mounted. | ||
77 | |||
78 | In addition, to avoid nesting many #ifdefs, we internally set | ||
79 | LDAV_DONE to indicate that the load average has been computed. | ||
80 | |||
81 | We also #define LDAV_PRIVILEGED if a program will require | ||
82 | special installation to be able to call getloadavg. */ | ||
83 | |||
84 | /* "configure" defines CONFIGURING_GETLOADAVG to sidestep problems | ||
85 | with partially-configured source directories. */ | ||
86 | |||
87 | #ifndef CONFIGURING_GETLOADAVG | ||
88 | # include <config.h> | ||
89 | # include <stdbool.h> | ||
90 | #endif | ||
91 | |||
92 | #include <errno.h> | ||
93 | #include <stdio.h> | ||
94 | #include <stdlib.h> | ||
95 | |||
96 | /* Exclude all the code except the test program at the end | ||
97 | if the system has its own `getloadavg' function. */ | ||
98 | |||
99 | #ifndef HAVE_GETLOADAVG | ||
100 | |||
101 | # include <sys/types.h> | ||
102 | |||
103 | /* Both the Emacs and non-Emacs sections want this. Some | ||
104 | configuration files' definitions for the LOAD_AVE_CVT macro (like | ||
105 | sparc.h's) use macros like FSCALE, defined here. */ | ||
106 | # if defined (unix) || defined (__unix) | ||
107 | # include <sys/param.h> | ||
108 | # endif | ||
109 | |||
110 | # include "c-strtod.h" | ||
111 | # include "cloexec.h" | ||
112 | # include "intprops.h" | ||
113 | # include "xalloc.h" | ||
114 | |||
115 | /* The existing Emacs configuration files define a macro called | ||
116 | LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and | ||
117 | returns the load average multiplied by 100. What we actually want | ||
118 | is a macro called LDAV_CVT, which returns the load average as an | ||
119 | unmultiplied double. | ||
120 | |||
121 | For backwards compatibility, we'll define LDAV_CVT in terms of | ||
122 | LOAD_AVE_CVT, but future machine config files should just define | ||
123 | LDAV_CVT directly. */ | ||
124 | |||
125 | # if !defined (LDAV_CVT) && defined (LOAD_AVE_CVT) | ||
126 | # define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0) | ||
127 | # endif | ||
128 | |||
129 | # if !defined (BSD) && defined (ultrix) | ||
130 | /* Ultrix behaves like BSD on Vaxen. */ | ||
131 | # define BSD | ||
132 | # endif | ||
133 | |||
134 | # ifdef NeXT | ||
135 | /* NeXT in the 2.{0,1,2} releases defines BSD in <sys/param.h>, which | ||
136 | conflicts with the definition understood in this file, that this | ||
137 | really is BSD. */ | ||
138 | # undef BSD | ||
139 | |||
140 | /* NeXT defines FSCALE in <sys/param.h>. However, we take FSCALE being | ||
141 | defined to mean that the nlist method should be used, which is not true. */ | ||
142 | # undef FSCALE | ||
143 | # endif | ||
144 | |||
145 | /* Same issues as for NeXT apply to the HURD-based GNU system. */ | ||
146 | # ifdef __GNU__ | ||
147 | # undef BSD | ||
148 | # undef FSCALE | ||
149 | # endif /* __GNU__ */ | ||
150 | |||
151 | /* Set values that are different from the defaults, which are | ||
152 | set a little farther down with #ifndef. */ | ||
153 | |||
154 | |||
155 | /* Some shorthands. */ | ||
156 | |||
157 | # if defined (HPUX) && !defined (hpux) | ||
158 | # define hpux | ||
159 | # endif | ||
160 | |||
161 | # if defined (__hpux) && !defined (hpux) | ||
162 | # define hpux | ||
163 | # endif | ||
164 | |||
165 | # if defined (__sun) && !defined (sun) | ||
166 | # define sun | ||
167 | # endif | ||
168 | |||
169 | # if defined (hp300) && !defined (hpux) | ||
170 | # define MORE_BSD | ||
171 | # endif | ||
172 | |||
173 | # if defined (ultrix) && defined (mips) | ||
174 | # define decstation | ||
175 | # endif | ||
176 | |||
177 | # if defined (__SVR4) && !defined (SVR4) | ||
178 | # define SVR4 | ||
179 | # endif | ||
180 | |||
181 | # if (defined (sun) && defined (SVR4)) || defined (SOLARIS2) | ||
182 | # define SUNOS_5 | ||
183 | # endif | ||
184 | |||
185 | # if defined (__osf__) && (defined (__alpha) || defined (__alpha__)) | ||
186 | # define OSF_ALPHA | ||
187 | # include <sys/mbuf.h> | ||
188 | # include <sys/socket.h> | ||
189 | # include <net/route.h> | ||
190 | # include <sys/table.h> | ||
191 | # endif | ||
192 | |||
193 | # if defined (__osf__) && (defined (mips) || defined (__mips__)) | ||
194 | # define OSF_MIPS | ||
195 | # include <sys/table.h> | ||
196 | # endif | ||
197 | |||
198 | /* UTek's /bin/cc on the 4300 has no architecture specific cpp define by | ||
199 | default, but _MACH_IND_SYS_TYPES is defined in <sys/types.h>. Combine | ||
200 | that with a couple of other things and we'll have a unique match. */ | ||
201 | # if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES) | ||
202 | # define tek4300 /* Define by emacs, but not by other users. */ | ||
203 | # endif | ||
204 | |||
205 | |||
206 | /* VAX C can't handle multi-line #ifs, or lines longer than 256 chars. */ | ||
207 | # ifndef LOAD_AVE_TYPE | ||
208 | |||
209 | # ifdef MORE_BSD | ||
210 | # define LOAD_AVE_TYPE long | ||
211 | # endif | ||
212 | |||
213 | # ifdef sun | ||
214 | # define LOAD_AVE_TYPE long | ||
215 | # endif | ||
216 | |||
217 | # ifdef decstation | ||
218 | # define LOAD_AVE_TYPE long | ||
219 | # endif | ||
220 | |||
221 | # ifdef _SEQUENT_ | ||
222 | # define LOAD_AVE_TYPE long | ||
223 | # endif | ||
224 | |||
225 | # ifdef sgi | ||
226 | # define LOAD_AVE_TYPE long | ||
227 | # endif | ||
228 | |||
229 | # ifdef SVR4 | ||
230 | # define LOAD_AVE_TYPE long | ||
231 | # endif | ||
232 | |||
233 | # ifdef sony_news | ||
234 | # define LOAD_AVE_TYPE long | ||
235 | # endif | ||
236 | |||
237 | # ifdef sequent | ||
238 | # define LOAD_AVE_TYPE long | ||
239 | # endif | ||
240 | |||
241 | # ifdef OSF_ALPHA | ||
242 | # define LOAD_AVE_TYPE long | ||
243 | # endif | ||
244 | |||
245 | # if defined (ardent) && defined (titan) | ||
246 | # define LOAD_AVE_TYPE long | ||
247 | # endif | ||
248 | |||
249 | # ifdef tek4300 | ||
250 | # define LOAD_AVE_TYPE long | ||
251 | # endif | ||
252 | |||
253 | # if defined (alliant) && defined (i860) /* Alliant FX/2800 */ | ||
254 | # define LOAD_AVE_TYPE long | ||
255 | # endif | ||
256 | |||
257 | # ifdef _AIX | ||
258 | # define LOAD_AVE_TYPE long | ||
259 | # endif | ||
260 | |||
261 | # ifdef convex | ||
262 | # define LOAD_AVE_TYPE double | ||
263 | # ifndef LDAV_CVT | ||
264 | # define LDAV_CVT(n) (n) | ||
265 | # endif | ||
266 | # endif | ||
267 | |||
268 | # endif /* No LOAD_AVE_TYPE. */ | ||
269 | |||
270 | # ifdef OSF_ALPHA | ||
271 | /* <sys/param.h> defines an incorrect value for FSCALE on Alpha OSF/1, | ||
272 | according to ghazi@noc.rutgers.edu. */ | ||
273 | # undef FSCALE | ||
274 | # define FSCALE 1024.0 | ||
275 | # endif | ||
276 | |||
277 | # if defined (alliant) && defined (i860) /* Alliant FX/2800 */ | ||
278 | /* <sys/param.h> defines an incorrect value for FSCALE on an | ||
279 | Alliant FX/2800 Concentrix 2.2, according to ghazi@noc.rutgers.edu. */ | ||
280 | # undef FSCALE | ||
281 | # define FSCALE 100.0 | ||
282 | # endif | ||
283 | |||
284 | |||
285 | # ifndef FSCALE | ||
286 | |||
287 | /* SunOS and some others define FSCALE in sys/param.h. */ | ||
288 | |||
289 | # ifdef MORE_BSD | ||
290 | # define FSCALE 2048.0 | ||
291 | # endif | ||
292 | |||
293 | # if defined (MIPS) || defined (SVR4) || defined (decstation) | ||
294 | # define FSCALE 256 | ||
295 | # endif | ||
296 | |||
297 | # if defined (sgi) || defined (sequent) | ||
298 | /* Sometimes both MIPS and sgi are defined, so FSCALE was just defined | ||
299 | above under #ifdef MIPS. But we want the sgi value. */ | ||
300 | # undef FSCALE | ||
301 | # define FSCALE 1000.0 | ||
302 | # endif | ||
303 | |||
304 | # if defined (ardent) && defined (titan) | ||
305 | # define FSCALE 65536.0 | ||
306 | # endif | ||
307 | |||
308 | # ifdef tek4300 | ||
309 | # define FSCALE 100.0 | ||
310 | # endif | ||
311 | |||
312 | # ifdef _AIX | ||
313 | # define FSCALE 65536.0 | ||
314 | # endif | ||
315 | |||
316 | # endif /* Not FSCALE. */ | ||
317 | |||
318 | # if !defined (LDAV_CVT) && defined (FSCALE) | ||
319 | # define LDAV_CVT(n) (((double) (n)) / FSCALE) | ||
320 | # endif | ||
321 | |||
322 | # ifndef NLIST_STRUCT | ||
323 | # if HAVE_NLIST_H | ||
324 | # define NLIST_STRUCT | ||
325 | # endif | ||
326 | # endif | ||
327 | |||
328 | # if defined (sgi) || (defined (mips) && !defined (BSD)) | ||
329 | # define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31)) | ||
330 | # endif | ||
331 | |||
332 | |||
333 | # if !defined (KERNEL_FILE) && defined (sequent) | ||
334 | # define KERNEL_FILE "/dynix" | ||
335 | # endif | ||
336 | |||
337 | # if !defined (KERNEL_FILE) && defined (hpux) | ||
338 | # define KERNEL_FILE "/hp-ux" | ||
339 | # endif | ||
340 | |||
341 | # if !defined (KERNEL_FILE) && (defined (_SEQUENT_) || defined (MIPS) || defined (SVR4) || defined (ISC) || defined (sgi) || (defined (ardent) && defined (titan))) | ||
342 | # define KERNEL_FILE "/unix" | ||
343 | # endif | ||
344 | |||
345 | |||
346 | # if !defined (LDAV_SYMBOL) && defined (alliant) | ||
347 | # define LDAV_SYMBOL "_Loadavg" | ||
348 | # endif | ||
349 | |||
350 | # if !defined (LDAV_SYMBOL) && ((defined (hpux) && !defined (hp9000s300)) || defined (_SEQUENT_) || defined (SVR4) || defined (ISC) || defined (sgi) || (defined (ardent) && defined (titan)) || defined (_AIX)) | ||
351 | # define LDAV_SYMBOL "avenrun" | ||
352 | # endif | ||
353 | |||
354 | # include <unistd.h> | ||
355 | |||
356 | /* LOAD_AVE_TYPE should only get defined if we're going to use the | ||
357 | nlist method. */ | ||
358 | # if !defined (LOAD_AVE_TYPE) && (defined (BSD) || defined (LDAV_CVT) || defined (KERNEL_FILE) || defined (LDAV_SYMBOL)) | ||
359 | # define LOAD_AVE_TYPE double | ||
360 | # endif | ||
361 | |||
362 | # ifdef LOAD_AVE_TYPE | ||
363 | |||
364 | # ifndef __VMS | ||
365 | # ifndef __linux__ | ||
366 | # ifndef NLIST_STRUCT | ||
367 | # include <a.out.h> | ||
368 | # else /* NLIST_STRUCT */ | ||
369 | # include <nlist.h> | ||
370 | # endif /* NLIST_STRUCT */ | ||
371 | |||
372 | # ifdef SUNOS_5 | ||
373 | # include <fcntl.h> | ||
374 | # include <kvm.h> | ||
375 | # include <kstat.h> | ||
376 | # endif | ||
377 | |||
378 | # if defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC) | ||
379 | # include <sys/pstat.h> | ||
380 | # endif | ||
381 | |||
382 | # ifndef KERNEL_FILE | ||
383 | # define KERNEL_FILE "/vmunix" | ||
384 | # endif /* KERNEL_FILE */ | ||
385 | |||
386 | # ifndef LDAV_SYMBOL | ||
387 | # define LDAV_SYMBOL "_avenrun" | ||
388 | # endif /* LDAV_SYMBOL */ | ||
389 | # endif /* __linux__ */ | ||
390 | |||
391 | # else /* __VMS */ | ||
392 | |||
393 | # ifndef eunice | ||
394 | # include <iodef.h> | ||
395 | # include <descrip.h> | ||
396 | # else /* eunice */ | ||
397 | # include <vms/iodef.h> | ||
398 | # endif /* eunice */ | ||
399 | # endif /* __VMS */ | ||
400 | |||
401 | # ifndef LDAV_CVT | ||
402 | # define LDAV_CVT(n) ((double) (n)) | ||
403 | # endif /* !LDAV_CVT */ | ||
404 | |||
405 | # endif /* LOAD_AVE_TYPE */ | ||
406 | |||
407 | # if defined (__GNU__) && !defined (NeXT) | ||
408 | /* Note that NeXT Openstep defines __GNU__ even though it should not. */ | ||
409 | /* GNU system acts much like NeXT, for load average purposes, | ||
410 | but not exactly. */ | ||
411 | # define NeXT | ||
412 | # define host_self mach_host_self | ||
413 | # endif | ||
414 | |||
415 | # ifdef NeXT | ||
416 | # ifdef HAVE_MACH_MACH_H | ||
417 | # include <mach/mach.h> | ||
418 | # else | ||
419 | # include <mach.h> | ||
420 | # endif | ||
421 | # endif /* NeXT */ | ||
422 | |||
423 | # ifdef sgi | ||
424 | # include <sys/sysmp.h> | ||
425 | # endif /* sgi */ | ||
426 | |||
427 | # ifdef UMAX | ||
428 | # include <signal.h> | ||
429 | # include <sys/time.h> | ||
430 | # include <sys/wait.h> | ||
431 | # include <sys/syscall.h> | ||
432 | |||
433 | # ifdef UMAX_43 | ||
434 | # include <machine/cpu.h> | ||
435 | # include <inq_stats/statistics.h> | ||
436 | # include <inq_stats/sysstats.h> | ||
437 | # include <inq_stats/cpustats.h> | ||
438 | # include <inq_stats/procstats.h> | ||
439 | # else /* Not UMAX_43. */ | ||
440 | # include <sys/sysdefs.h> | ||
441 | # include <sys/statistics.h> | ||
442 | # include <sys/sysstats.h> | ||
443 | # include <sys/cpudefs.h> | ||
444 | # include <sys/cpustats.h> | ||
445 | # include <sys/procstats.h> | ||
446 | # endif /* Not UMAX_43. */ | ||
447 | # endif /* UMAX */ | ||
448 | |||
449 | # ifdef DGUX | ||
450 | # include <sys/dg_sys_info.h> | ||
451 | # endif | ||
452 | |||
453 | # include "fcntl--.h" | ||
454 | |||
455 | /* Avoid static vars inside a function since in HPUX they dump as pure. */ | ||
456 | |||
457 | # ifdef NeXT | ||
458 | static processor_set_t default_set; | ||
459 | static bool getloadavg_initialized; | ||
460 | # endif /* NeXT */ | ||
461 | |||
462 | # ifdef UMAX | ||
463 | static unsigned int cpus = 0; | ||
464 | static unsigned int samples; | ||
465 | # endif /* UMAX */ | ||
466 | |||
467 | # ifdef DGUX | ||
468 | static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */ | ||
469 | # endif /* DGUX */ | ||
470 | |||
471 | # if !defined (HAVE_LIBKSTAT) && defined (LOAD_AVE_TYPE) | ||
472 | /* File descriptor open to /dev/kmem or VMS load ave driver. */ | ||
473 | static int channel; | ||
474 | /* True iff channel is valid. */ | ||
475 | static bool getloadavg_initialized; | ||
476 | /* Offset in kmem to seek to read load average, or 0 means invalid. */ | ||
477 | static long offset; | ||
478 | |||
479 | # if ! defined __VMS && ! defined sgi && ! defined __linux__ | ||
480 | static struct nlist nl[2]; | ||
481 | # endif | ||
482 | |||
483 | # ifdef SUNOS_5 | ||
484 | static kvm_t *kd; | ||
485 | # endif /* SUNOS_5 */ | ||
486 | |||
487 | # endif /* LOAD_AVE_TYPE && !HAVE_LIBKSTAT */ | ||
488 | |||
489 | /* Put the 1 minute, 5 minute and 15 minute load averages | ||
490 | into the first NELEM elements of LOADAVG. | ||
491 | Return the number written (never more than 3, but may be less than NELEM), | ||
492 | or -1 if an error occurred. */ | ||
493 | |||
494 | int | ||
495 | getloadavg (double loadavg[], int nelem) | ||
496 | { | ||
497 | int elem = 0; /* Return value. */ | ||
498 | |||
499 | # ifdef NO_GET_LOAD_AVG | ||
500 | # define LDAV_DONE | ||
501 | /* Set errno to zero to indicate that there was no particular error; | ||
502 | this function just can't work at all on this system. */ | ||
503 | errno = 0; | ||
504 | elem = -1; | ||
505 | # endif | ||
506 | |||
507 | # if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT) | ||
508 | /* Use libkstat because we don't have to be root. */ | ||
509 | # define LDAV_DONE | ||
510 | kstat_ctl_t *kc; | ||
511 | kstat_t *ksp; | ||
512 | kstat_named_t *kn; | ||
513 | |||
514 | kc = kstat_open (); | ||
515 | if (kc == 0) | ||
516 | return -1; | ||
517 | ksp = kstat_lookup (kc, "unix", 0, "system_misc"); | ||
518 | if (ksp == 0) | ||
519 | return -1; | ||
520 | if (kstat_read (kc, ksp, 0) == -1) | ||
521 | return -1; | ||
522 | |||
523 | |||
524 | kn = kstat_data_lookup (ksp, "avenrun_1min"); | ||
525 | if (kn == 0) | ||
526 | { | ||
527 | /* Return -1 if no load average information is available. */ | ||
528 | nelem = 0; | ||
529 | elem = -1; | ||
530 | } | ||
531 | |||
532 | if (nelem >= 1) | ||
533 | loadavg[elem++] = (double) kn->value.ul / FSCALE; | ||
534 | |||
535 | if (nelem >= 2) | ||
536 | { | ||
537 | kn = kstat_data_lookup (ksp, "avenrun_5min"); | ||
538 | if (kn != 0) | ||
539 | { | ||
540 | loadavg[elem++] = (double) kn->value.ul / FSCALE; | ||
541 | |||
542 | if (nelem >= 3) | ||
543 | { | ||
544 | kn = kstat_data_lookup (ksp, "avenrun_15min"); | ||
545 | if (kn != 0) | ||
546 | loadavg[elem++] = (double) kn->value.ul / FSCALE; | ||
547 | } | ||
548 | } | ||
549 | } | ||
550 | |||
551 | kstat_close (kc); | ||
552 | # endif /* HAVE_LIBKSTAT */ | ||
553 | |||
554 | # if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC) | ||
555 | /* Use pstat_getdynamic() because we don't have to be root. */ | ||
556 | # define LDAV_DONE | ||
557 | # undef LOAD_AVE_TYPE | ||
558 | |||
559 | struct pst_dynamic dyn_info; | ||
560 | if (pstat_getdynamic (&dyn_info, sizeof (dyn_info), 0, 0) < 0) | ||
561 | return -1; | ||
562 | if (nelem > 0) | ||
563 | loadavg[elem++] = dyn_info.psd_avg_1_min; | ||
564 | if (nelem > 1) | ||
565 | loadavg[elem++] = dyn_info.psd_avg_5_min; | ||
566 | if (nelem > 2) | ||
567 | loadavg[elem++] = dyn_info.psd_avg_15_min; | ||
568 | |||
569 | # endif /* hpux && HAVE_PSTAT_GETDYNAMIC */ | ||
570 | |||
571 | # if !defined (LDAV_DONE) && (defined (__linux__) || defined (__CYGWIN__)) | ||
572 | # define LDAV_DONE | ||
573 | # undef LOAD_AVE_TYPE | ||
574 | |||
575 | # ifndef LINUX_LDAV_FILE | ||
576 | # define LINUX_LDAV_FILE "/proc/loadavg" | ||
577 | # endif | ||
578 | |||
579 | char ldavgbuf[3 * (INT_STRLEN_BOUND (int) + sizeof ".00 ")]; | ||
580 | char const *ptr = ldavgbuf; | ||
581 | int fd, count; | ||
582 | |||
583 | fd = open (LINUX_LDAV_FILE, O_RDONLY); | ||
584 | if (fd == -1) | ||
585 | return -1; | ||
586 | count = read (fd, ldavgbuf, sizeof ldavgbuf - 1); | ||
587 | (void) close (fd); | ||
588 | if (count <= 0) | ||
589 | return -1; | ||
590 | ldavgbuf[count] = '\0'; | ||
591 | |||
592 | for (elem = 0; elem < nelem; elem++) | ||
593 | { | ||
594 | char *endptr; | ||
595 | double d = c_strtod (ptr, &endptr); | ||
596 | if (ptr == endptr) | ||
597 | { | ||
598 | if (elem == 0) | ||
599 | return -1; | ||
600 | break; | ||
601 | } | ||
602 | loadavg[elem] = d; | ||
603 | ptr = endptr; | ||
604 | } | ||
605 | |||
606 | return elem; | ||
607 | |||
608 | # endif /* __linux__ || __CYGWIN__ */ | ||
609 | |||
610 | # if !defined (LDAV_DONE) && defined (__NetBSD__) | ||
611 | # define LDAV_DONE | ||
612 | # undef LOAD_AVE_TYPE | ||
613 | |||
614 | # ifndef NETBSD_LDAV_FILE | ||
615 | # define NETBSD_LDAV_FILE "/kern/loadavg" | ||
616 | # endif | ||
617 | |||
618 | unsigned long int load_ave[3], scale; | ||
619 | int count; | ||
620 | FILE *fp; | ||
621 | |||
622 | fp = fopen (NETBSD_LDAV_FILE, "r"); | ||
623 | if (fp == NULL) | ||
624 | return -1; | ||
625 | count = fscanf (fp, "%lu %lu %lu %lu\n", | ||
626 | &load_ave[0], &load_ave[1], &load_ave[2], | ||
627 | &scale); | ||
628 | (void) fclose (fp); | ||
629 | if (count != 4) | ||
630 | return -1; | ||
631 | |||
632 | for (elem = 0; elem < nelem; elem++) | ||
633 | loadavg[elem] = (double) load_ave[elem] / (double) scale; | ||
634 | |||
635 | return elem; | ||
636 | |||
637 | # endif /* __NetBSD__ */ | ||
638 | |||
639 | # if !defined (LDAV_DONE) && defined (NeXT) | ||
640 | # define LDAV_DONE | ||
641 | /* The NeXT code was adapted from iscreen 3.2. */ | ||
642 | |||
643 | host_t host; | ||
644 | struct processor_set_basic_info info; | ||
645 | unsigned int info_count; | ||
646 | |||
647 | /* We only know how to get the 1-minute average for this system, | ||
648 | so even if the caller asks for more than 1, we only return 1. */ | ||
649 | |||
650 | if (!getloadavg_initialized) | ||
651 | { | ||
652 | if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS) | ||
653 | getloadavg_initialized = true; | ||
654 | } | ||
655 | |||
656 | if (getloadavg_initialized) | ||
657 | { | ||
658 | info_count = PROCESSOR_SET_BASIC_INFO_COUNT; | ||
659 | if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host, | ||
660 | (processor_set_info_t) &info, &info_count) | ||
661 | != KERN_SUCCESS) | ||
662 | getloadavg_initialized = false; | ||
663 | else | ||
664 | { | ||
665 | if (nelem > 0) | ||
666 | loadavg[elem++] = (double) info.load_average / LOAD_SCALE; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | if (!getloadavg_initialized) | ||
671 | return -1; | ||
672 | # endif /* NeXT */ | ||
673 | |||
674 | # if !defined (LDAV_DONE) && defined (UMAX) | ||
675 | # define LDAV_DONE | ||
676 | /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not | ||
677 | have a /dev/kmem. Information about the workings of the running kernel | ||
678 | can be gathered with inq_stats system calls. | ||
679 | We only know how to get the 1-minute average for this system. */ | ||
680 | |||
681 | struct proc_summary proc_sum_data; | ||
682 | struct stat_descr proc_info; | ||
683 | double load; | ||
684 | register unsigned int i, j; | ||
685 | |||
686 | if (cpus == 0) | ||
687 | { | ||
688 | register unsigned int c, i; | ||
689 | struct cpu_config conf; | ||
690 | struct stat_descr desc; | ||
691 | |||
692 | desc.sd_next = 0; | ||
693 | desc.sd_subsys = SUBSYS_CPU; | ||
694 | desc.sd_type = CPUTYPE_CONFIG; | ||
695 | desc.sd_addr = (char *) &conf; | ||
696 | desc.sd_size = sizeof conf; | ||
697 | |||
698 | if (inq_stats (1, &desc)) | ||
699 | return -1; | ||
700 | |||
701 | c = 0; | ||
702 | for (i = 0; i < conf.config_maxclass; ++i) | ||
703 | { | ||
704 | struct class_stats stats; | ||
705 | bzero ((char *) &stats, sizeof stats); | ||
706 | |||
707 | desc.sd_type = CPUTYPE_CLASS; | ||
708 | desc.sd_objid = i; | ||
709 | desc.sd_addr = (char *) &stats; | ||
710 | desc.sd_size = sizeof stats; | ||
711 | |||
712 | if (inq_stats (1, &desc)) | ||
713 | return -1; | ||
714 | |||
715 | c += stats.class_numcpus; | ||
716 | } | ||
717 | cpus = c; | ||
718 | samples = cpus < 2 ? 3 : (2 * cpus / 3); | ||
719 | } | ||
720 | |||
721 | proc_info.sd_next = 0; | ||
722 | proc_info.sd_subsys = SUBSYS_PROC; | ||
723 | proc_info.sd_type = PROCTYPE_SUMMARY; | ||
724 | proc_info.sd_addr = (char *) &proc_sum_data; | ||
725 | proc_info.sd_size = sizeof (struct proc_summary); | ||
726 | proc_info.sd_sizeused = 0; | ||
727 | |||
728 | if (inq_stats (1, &proc_info) != 0) | ||
729 | return -1; | ||
730 | |||
731 | load = proc_sum_data.ps_nrunnable; | ||
732 | j = 0; | ||
733 | for (i = samples - 1; i > 0; --i) | ||
734 | { | ||
735 | load += proc_sum_data.ps_nrun[j]; | ||
736 | if (j++ == PS_NRUNSIZE) | ||
737 | j = 0; | ||
738 | } | ||
739 | |||
740 | if (nelem > 0) | ||
741 | loadavg[elem++] = load / samples / cpus; | ||
742 | # endif /* UMAX */ | ||
743 | |||
744 | # if !defined (LDAV_DONE) && defined (DGUX) | ||
745 | # define LDAV_DONE | ||
746 | /* This call can return -1 for an error, but with good args | ||
747 | it's not supposed to fail. The first argument is for no | ||
748 | apparent reason of type `long int *'. */ | ||
749 | dg_sys_info ((long int *) &load_info, | ||
750 | DG_SYS_INFO_LOAD_INFO_TYPE, | ||
751 | DG_SYS_INFO_LOAD_VERSION_0); | ||
752 | |||
753 | if (nelem > 0) | ||
754 | loadavg[elem++] = load_info.one_minute; | ||
755 | if (nelem > 1) | ||
756 | loadavg[elem++] = load_info.five_minute; | ||
757 | if (nelem > 2) | ||
758 | loadavg[elem++] = load_info.fifteen_minute; | ||
759 | # endif /* DGUX */ | ||
760 | |||
761 | # if !defined (LDAV_DONE) && defined (apollo) | ||
762 | # define LDAV_DONE | ||
763 | /* Apollo code from lisch@mentorg.com (Ray Lischner). | ||
764 | |||
765 | This system call is not documented. The load average is obtained as | ||
766 | three long integers, for the load average over the past minute, | ||
767 | five minutes, and fifteen minutes. Each value is a scaled integer, | ||
768 | with 16 bits of integer part and 16 bits of fraction part. | ||
769 | |||
770 | I'm not sure which operating system first supported this system call, | ||
771 | but I know that SR10.2 supports it. */ | ||
772 | |||
773 | extern void proc1_$get_loadav (); | ||
774 | unsigned long load_ave[3]; | ||
775 | |||
776 | proc1_$get_loadav (load_ave); | ||
777 | |||
778 | if (nelem > 0) | ||
779 | loadavg[elem++] = load_ave[0] / 65536.0; | ||
780 | if (nelem > 1) | ||
781 | loadavg[elem++] = load_ave[1] / 65536.0; | ||
782 | if (nelem > 2) | ||
783 | loadavg[elem++] = load_ave[2] / 65536.0; | ||
784 | # endif /* apollo */ | ||
785 | |||
786 | # if !defined (LDAV_DONE) && defined (OSF_MIPS) | ||
787 | # define LDAV_DONE | ||
788 | |||
789 | struct tbl_loadavg load_ave; | ||
790 | table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave)); | ||
791 | loadavg[elem++] | ||
792 | = (load_ave.tl_lscale == 0 | ||
793 | ? load_ave.tl_avenrun.d[0] | ||
794 | : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale)); | ||
795 | # endif /* OSF_MIPS */ | ||
796 | |||
797 | # if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32)) | ||
798 | # define LDAV_DONE | ||
799 | |||
800 | /* A faithful emulation is going to have to be saved for a rainy day. */ | ||
801 | for ( ; elem < nelem; elem++) | ||
802 | { | ||
803 | loadavg[elem] = 0.0; | ||
804 | } | ||
805 | # endif /* __MSDOS__ || WINDOWS32 */ | ||
806 | |||
807 | # if !defined (LDAV_DONE) && defined (OSF_ALPHA) | ||
808 | # define LDAV_DONE | ||
809 | |||
810 | struct tbl_loadavg load_ave; | ||
811 | table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave)); | ||
812 | for (elem = 0; elem < nelem; elem++) | ||
813 | loadavg[elem] | ||
814 | = (load_ave.tl_lscale == 0 | ||
815 | ? load_ave.tl_avenrun.d[elem] | ||
816 | : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale)); | ||
817 | # endif /* OSF_ALPHA */ | ||
818 | |||
819 | # if ! defined LDAV_DONE && defined __VMS | ||
820 | /* VMS specific code -- read from the Load Ave driver. */ | ||
821 | |||
822 | LOAD_AVE_TYPE load_ave[3]; | ||
823 | static bool getloadavg_initialized; | ||
824 | # ifdef eunice | ||
825 | struct | ||
826 | { | ||
827 | int dsc$w_length; | ||
828 | char *dsc$a_pointer; | ||
829 | } descriptor; | ||
830 | # endif | ||
831 | |||
832 | /* Ensure that there is a channel open to the load ave device. */ | ||
833 | if (!getloadavg_initialized) | ||
834 | { | ||
835 | /* Attempt to open the channel. */ | ||
836 | # ifdef eunice | ||
837 | descriptor.dsc$w_length = 18; | ||
838 | descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE"; | ||
839 | # else | ||
840 | $DESCRIPTOR (descriptor, "LAV0:"); | ||
841 | # endif | ||
842 | if (sys$assign (&descriptor, &channel, 0, 0) & 1) | ||
843 | getloadavg_initialized = true; | ||
844 | } | ||
845 | |||
846 | /* Read the load average vector. */ | ||
847 | if (getloadavg_initialized | ||
848 | && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0, | ||
849 | load_ave, 12, 0, 0, 0, 0) & 1)) | ||
850 | { | ||
851 | sys$dassgn (channel); | ||
852 | getloadavg_initialized = false; | ||
853 | } | ||
854 | |||
855 | if (!getloadavg_initialized) | ||
856 | return -1; | ||
857 | # endif /* ! defined LDAV_DONE && defined __VMS */ | ||
858 | |||
859 | # if ! defined LDAV_DONE && defined LOAD_AVE_TYPE && ! defined __VMS | ||
860 | |||
861 | /* UNIX-specific code -- read the average from /dev/kmem. */ | ||
862 | |||
863 | # define LDAV_PRIVILEGED /* This code requires special installation. */ | ||
864 | |||
865 | LOAD_AVE_TYPE load_ave[3]; | ||
866 | |||
867 | /* Get the address of LDAV_SYMBOL. */ | ||
868 | if (offset == 0) | ||
869 | { | ||
870 | # ifndef sgi | ||
871 | # ifndef NLIST_STRUCT | ||
872 | strcpy (nl[0].n_name, LDAV_SYMBOL); | ||
873 | strcpy (nl[1].n_name, ""); | ||
874 | # else /* NLIST_STRUCT */ | ||
875 | # ifdef HAVE_STRUCT_NLIST_N_UN_N_NAME | ||
876 | nl[0].n_un.n_name = LDAV_SYMBOL; | ||
877 | nl[1].n_un.n_name = 0; | ||
878 | # else /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */ | ||
879 | nl[0].n_name = LDAV_SYMBOL; | ||
880 | nl[1].n_name = 0; | ||
881 | # endif /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */ | ||
882 | # endif /* NLIST_STRUCT */ | ||
883 | |||
884 | # ifndef SUNOS_5 | ||
885 | if ( | ||
886 | # if !(defined (_AIX) && !defined (ps2)) | ||
887 | nlist (KERNEL_FILE, nl) | ||
888 | # else /* _AIX */ | ||
889 | knlist (nl, 1, sizeof (nl[0])) | ||
890 | # endif | ||
891 | >= 0) | ||
892 | /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */ | ||
893 | { | ||
894 | # ifdef FIXUP_KERNEL_SYMBOL_ADDR | ||
895 | FIXUP_KERNEL_SYMBOL_ADDR (nl); | ||
896 | # endif | ||
897 | offset = nl[0].n_value; | ||
898 | } | ||
899 | # endif /* !SUNOS_5 */ | ||
900 | # else /* sgi */ | ||
901 | int ldav_off; | ||
902 | |||
903 | ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN); | ||
904 | if (ldav_off != -1) | ||
905 | offset = (long int) ldav_off & 0x7fffffff; | ||
906 | # endif /* sgi */ | ||
907 | } | ||
908 | |||
909 | /* Make sure we have /dev/kmem open. */ | ||
910 | if (!getloadavg_initialized) | ||
911 | { | ||
912 | # ifndef SUNOS_5 | ||
913 | channel = open ("/dev/kmem", O_RDONLY); | ||
914 | if (channel >= 0) | ||
915 | { | ||
916 | /* Set the channel to close on exec, so it does not | ||
917 | litter any child's descriptor table. */ | ||
918 | set_cloexec_flag (channel, true); | ||
919 | getloadavg_initialized = true; | ||
920 | } | ||
921 | # else /* SUNOS_5 */ | ||
922 | /* We pass 0 for the kernel, corefile, and swapfile names | ||
923 | to use the currently running kernel. */ | ||
924 | kd = kvm_open (0, 0, 0, O_RDONLY, 0); | ||
925 | if (kd != 0) | ||
926 | { | ||
927 | /* nlist the currently running kernel. */ | ||
928 | kvm_nlist (kd, nl); | ||
929 | offset = nl[0].n_value; | ||
930 | getloadavg_initialized = true; | ||
931 | } | ||
932 | # endif /* SUNOS_5 */ | ||
933 | } | ||
934 | |||
935 | /* If we can, get the load average values. */ | ||
936 | if (offset && getloadavg_initialized) | ||
937 | { | ||
938 | /* Try to read the load. */ | ||
939 | # ifndef SUNOS_5 | ||
940 | if (lseek (channel, offset, 0) == -1L | ||
941 | || read (channel, (char *) load_ave, sizeof (load_ave)) | ||
942 | != sizeof (load_ave)) | ||
943 | { | ||
944 | close (channel); | ||
945 | getloadavg_initialized = false; | ||
946 | } | ||
947 | # else /* SUNOS_5 */ | ||
948 | if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave)) | ||
949 | != sizeof (load_ave)) | ||
950 | { | ||
951 | kvm_close (kd); | ||
952 | getloadavg_initialized = false; | ||
953 | } | ||
954 | # endif /* SUNOS_5 */ | ||
955 | } | ||
956 | |||
957 | if (offset == 0 || !getloadavg_initialized) | ||
958 | return -1; | ||
959 | # endif /* ! defined LDAV_DONE && defined LOAD_AVE_TYPE && ! defined __VMS */ | ||
960 | |||
961 | # if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS. */ | ||
962 | if (nelem > 0) | ||
963 | loadavg[elem++] = LDAV_CVT (load_ave[0]); | ||
964 | if (nelem > 1) | ||
965 | loadavg[elem++] = LDAV_CVT (load_ave[1]); | ||
966 | if (nelem > 2) | ||
967 | loadavg[elem++] = LDAV_CVT (load_ave[2]); | ||
968 | |||
969 | # define LDAV_DONE | ||
970 | # endif /* !LDAV_DONE && LOAD_AVE_TYPE */ | ||
971 | |||
972 | # if !defined LDAV_DONE | ||
973 | /* Set errno to zero to indicate that there was no particular error; | ||
974 | this function just can't work at all on this system. */ | ||
975 | errno = 0; | ||
976 | elem = -1; | ||
977 | # endif | ||
978 | return elem; | ||
979 | } | ||
980 | |||
981 | #endif /* ! HAVE_GETLOADAVG */ | ||
982 | |||
983 | #ifdef TEST | ||
984 | int | ||
985 | main (int argc, char **argv) | ||
986 | { | ||
987 | int naptime = 0; | ||
988 | |||
989 | if (argc > 1) | ||
990 | naptime = atoi (argv[1]); | ||
991 | |||
992 | while (1) | ||
993 | { | ||
994 | double avg[3]; | ||
995 | int loads; | ||
996 | |||
997 | errno = 0; /* Don't be misled if it doesn't set errno. */ | ||
998 | loads = getloadavg (avg, 3); | ||
999 | if (loads == -1) | ||
1000 | { | ||
1001 | perror ("Error getting load average"); | ||
1002 | return EXIT_FAILURE; | ||
1003 | } | ||
1004 | if (loads > 0) | ||
1005 | printf ("1-minute: %f ", avg[0]); | ||
1006 | if (loads > 1) | ||
1007 | printf ("5-minute: %f ", avg[1]); | ||
1008 | if (loads > 2) | ||
1009 | printf ("15-minute: %f ", avg[2]); | ||
1010 | if (loads > 0) | ||
1011 | putchar ('\n'); | ||
1012 | |||
1013 | if (naptime == 0) | ||
1014 | break; | ||
1015 | sleep (naptime); | ||
1016 | } | ||
1017 | |||
1018 | return EXIT_SUCCESS; | ||
1019 | } | ||
1020 | #endif /* TEST */ | ||
diff --git a/gl/getopt.c b/gl/getopt.c new file mode 100644 index 00000000..3580ad82 --- /dev/null +++ b/gl/getopt.c | |||
@@ -0,0 +1,1191 @@ | |||
1 | /* Getopt for GNU. | ||
2 | NOTE: getopt is now part of the C library, so if you don't know what | ||
3 | "Keep this file name-space clean" means, talk to drepper@gnu.org | ||
4 | before changing it! | ||
5 | Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001,2002,2003,2004,2006 | ||
6 | Free Software Foundation, Inc. | ||
7 | This file is part of the GNU C Library. | ||
8 | |||
9 | This program is free software; you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License as published by | ||
11 | the Free Software Foundation; either version 2, or (at your option) | ||
12 | any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License along | ||
20 | with this program; if not, write to the Free Software Foundation, | ||
21 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
22 | |||
23 | #ifndef _LIBC | ||
24 | # include <config.h> | ||
25 | #endif | ||
26 | |||
27 | #include "getopt.h" | ||
28 | |||
29 | #include <stdio.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <string.h> | ||
32 | #include <unistd.h> | ||
33 | |||
34 | #ifdef __VMS | ||
35 | # include <unixlib.h> | ||
36 | #endif | ||
37 | |||
38 | #ifdef _LIBC | ||
39 | # include <libintl.h> | ||
40 | #else | ||
41 | # include "gettext.h" | ||
42 | # define _(msgid) gettext (msgid) | ||
43 | #endif | ||
44 | |||
45 | #if defined _LIBC && defined USE_IN_LIBIO | ||
46 | # include <wchar.h> | ||
47 | #endif | ||
48 | |||
49 | #ifndef attribute_hidden | ||
50 | # define attribute_hidden | ||
51 | #endif | ||
52 | |||
53 | /* Unlike standard Unix `getopt', functions like `getopt_long' | ||
54 | let the user intersperse the options with the other arguments. | ||
55 | |||
56 | As `getopt_long' works, it permutes the elements of ARGV so that, | ||
57 | when it is done, all the options precede everything else. Thus | ||
58 | all application programs are extended to handle flexible argument order. | ||
59 | |||
60 | Using `getopt' or setting the environment variable POSIXLY_CORRECT | ||
61 | disables permutation. | ||
62 | Then the application's behavior is completely standard. | ||
63 | |||
64 | GNU application programs can use a third alternative mode in which | ||
65 | they can distinguish the relative order of options and other arguments. */ | ||
66 | |||
67 | #include "getopt_int.h" | ||
68 | |||
69 | /* For communication from `getopt' to the caller. | ||
70 | When `getopt' finds an option that takes an argument, | ||
71 | the argument value is returned here. | ||
72 | Also, when `ordering' is RETURN_IN_ORDER, | ||
73 | each non-option ARGV-element is returned here. */ | ||
74 | |||
75 | char *optarg; | ||
76 | |||
77 | /* Index in ARGV of the next element to be scanned. | ||
78 | This is used for communication to and from the caller | ||
79 | and for communication between successive calls to `getopt'. | ||
80 | |||
81 | On entry to `getopt', zero means this is the first call; initialize. | ||
82 | |||
83 | When `getopt' returns -1, this is the index of the first of the | ||
84 | non-option elements that the caller should itself scan. | ||
85 | |||
86 | Otherwise, `optind' communicates from one call to the next | ||
87 | how much of ARGV has been scanned so far. */ | ||
88 | |||
89 | /* 1003.2 says this must be 1 before any call. */ | ||
90 | int optind = 1; | ||
91 | |||
92 | /* Callers store zero here to inhibit the error message | ||
93 | for unrecognized options. */ | ||
94 | |||
95 | int opterr = 1; | ||
96 | |||
97 | /* Set to an option character which was unrecognized. | ||
98 | This must be initialized on some systems to avoid linking in the | ||
99 | system's own getopt implementation. */ | ||
100 | |||
101 | int optopt = '?'; | ||
102 | |||
103 | /* Keep a global copy of all internal members of getopt_data. */ | ||
104 | |||
105 | static struct _getopt_data getopt_data; | ||
106 | |||
107 | |||
108 | #if defined HAVE_DECL_GETENV && !HAVE_DECL_GETENV | ||
109 | extern char *getenv (); | ||
110 | #endif | ||
111 | |||
112 | #ifdef _LIBC | ||
113 | /* Stored original parameters. | ||
114 | XXX This is no good solution. We should rather copy the args so | ||
115 | that we can compare them later. But we must not use malloc(3). */ | ||
116 | extern int __libc_argc; | ||
117 | extern char **__libc_argv; | ||
118 | |||
119 | /* Bash 2.0 gives us an environment variable containing flags | ||
120 | indicating ARGV elements that should not be considered arguments. */ | ||
121 | |||
122 | # ifdef USE_NONOPTION_FLAGS | ||
123 | /* Defined in getopt_init.c */ | ||
124 | extern char *__getopt_nonoption_flags; | ||
125 | # endif | ||
126 | |||
127 | # ifdef USE_NONOPTION_FLAGS | ||
128 | # define SWAP_FLAGS(ch1, ch2) \ | ||
129 | if (d->__nonoption_flags_len > 0) \ | ||
130 | { \ | ||
131 | char __tmp = __getopt_nonoption_flags[ch1]; \ | ||
132 | __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ | ||
133 | __getopt_nonoption_flags[ch2] = __tmp; \ | ||
134 | } | ||
135 | # else | ||
136 | # define SWAP_FLAGS(ch1, ch2) | ||
137 | # endif | ||
138 | #else /* !_LIBC */ | ||
139 | # define SWAP_FLAGS(ch1, ch2) | ||
140 | #endif /* _LIBC */ | ||
141 | |||
142 | /* Exchange two adjacent subsequences of ARGV. | ||
143 | One subsequence is elements [first_nonopt,last_nonopt) | ||
144 | which contains all the non-options that have been skipped so far. | ||
145 | The other is elements [last_nonopt,optind), which contains all | ||
146 | the options processed since those non-options were skipped. | ||
147 | |||
148 | `first_nonopt' and `last_nonopt' are relocated so that they describe | ||
149 | the new indices of the non-options in ARGV after they are moved. */ | ||
150 | |||
151 | static void | ||
152 | exchange (char **argv, struct _getopt_data *d) | ||
153 | { | ||
154 | int bottom = d->__first_nonopt; | ||
155 | int middle = d->__last_nonopt; | ||
156 | int top = d->optind; | ||
157 | char *tem; | ||
158 | |||
159 | /* Exchange the shorter segment with the far end of the longer segment. | ||
160 | That puts the shorter segment into the right place. | ||
161 | It leaves the longer segment in the right place overall, | ||
162 | but it consists of two parts that need to be swapped next. */ | ||
163 | |||
164 | #if defined _LIBC && defined USE_NONOPTION_FLAGS | ||
165 | /* First make sure the handling of the `__getopt_nonoption_flags' | ||
166 | string can work normally. Our top argument must be in the range | ||
167 | of the string. */ | ||
168 | if (d->__nonoption_flags_len > 0 && top >= d->__nonoption_flags_max_len) | ||
169 | { | ||
170 | /* We must extend the array. The user plays games with us and | ||
171 | presents new arguments. */ | ||
172 | char *new_str = malloc (top + 1); | ||
173 | if (new_str == NULL) | ||
174 | d->__nonoption_flags_len = d->__nonoption_flags_max_len = 0; | ||
175 | else | ||
176 | { | ||
177 | memset (__mempcpy (new_str, __getopt_nonoption_flags, | ||
178 | d->__nonoption_flags_max_len), | ||
179 | '\0', top + 1 - d->__nonoption_flags_max_len); | ||
180 | d->__nonoption_flags_max_len = top + 1; | ||
181 | __getopt_nonoption_flags = new_str; | ||
182 | } | ||
183 | } | ||
184 | #endif | ||
185 | |||
186 | while (top > middle && middle > bottom) | ||
187 | { | ||
188 | if (top - middle > middle - bottom) | ||
189 | { | ||
190 | /* Bottom segment is the short one. */ | ||
191 | int len = middle - bottom; | ||
192 | register int i; | ||
193 | |||
194 | /* Swap it with the top part of the top segment. */ | ||
195 | for (i = 0; i < len; i++) | ||
196 | { | ||
197 | tem = argv[bottom + i]; | ||
198 | argv[bottom + i] = argv[top - (middle - bottom) + i]; | ||
199 | argv[top - (middle - bottom) + i] = tem; | ||
200 | SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); | ||
201 | } | ||
202 | /* Exclude the moved bottom segment from further swapping. */ | ||
203 | top -= len; | ||
204 | } | ||
205 | else | ||
206 | { | ||
207 | /* Top segment is the short one. */ | ||
208 | int len = top - middle; | ||
209 | register int i; | ||
210 | |||
211 | /* Swap it with the bottom part of the bottom segment. */ | ||
212 | for (i = 0; i < len; i++) | ||
213 | { | ||
214 | tem = argv[bottom + i]; | ||
215 | argv[bottom + i] = argv[middle + i]; | ||
216 | argv[middle + i] = tem; | ||
217 | SWAP_FLAGS (bottom + i, middle + i); | ||
218 | } | ||
219 | /* Exclude the moved top segment from further swapping. */ | ||
220 | bottom += len; | ||
221 | } | ||
222 | } | ||
223 | |||
224 | /* Update records for the slots the non-options now occupy. */ | ||
225 | |||
226 | d->__first_nonopt += (d->optind - d->__last_nonopt); | ||
227 | d->__last_nonopt = d->optind; | ||
228 | } | ||
229 | |||
230 | /* Initialize the internal data when the first call is made. */ | ||
231 | |||
232 | static const char * | ||
233 | _getopt_initialize (int argc, char **argv, const char *optstring, | ||
234 | int posixly_correct, struct _getopt_data *d) | ||
235 | { | ||
236 | /* Start processing options with ARGV-element 1 (since ARGV-element 0 | ||
237 | is the program name); the sequence of previously skipped | ||
238 | non-option ARGV-elements is empty. */ | ||
239 | |||
240 | d->__first_nonopt = d->__last_nonopt = d->optind; | ||
241 | |||
242 | d->__nextchar = NULL; | ||
243 | |||
244 | d->__posixly_correct = posixly_correct || !!getenv ("POSIXLY_CORRECT"); | ||
245 | |||
246 | /* Determine how to handle the ordering of options and nonoptions. */ | ||
247 | |||
248 | if (optstring[0] == '-') | ||
249 | { | ||
250 | d->__ordering = RETURN_IN_ORDER; | ||
251 | ++optstring; | ||
252 | } | ||
253 | else if (optstring[0] == '+') | ||
254 | { | ||
255 | d->__ordering = REQUIRE_ORDER; | ||
256 | ++optstring; | ||
257 | } | ||
258 | else if (d->__posixly_correct) | ||
259 | d->__ordering = REQUIRE_ORDER; | ||
260 | else | ||
261 | d->__ordering = PERMUTE; | ||
262 | |||
263 | #if defined _LIBC && defined USE_NONOPTION_FLAGS | ||
264 | if (!d->__posixly_correct | ||
265 | && argc == __libc_argc && argv == __libc_argv) | ||
266 | { | ||
267 | if (d->__nonoption_flags_max_len == 0) | ||
268 | { | ||
269 | if (__getopt_nonoption_flags == NULL | ||
270 | || __getopt_nonoption_flags[0] == '\0') | ||
271 | d->__nonoption_flags_max_len = -1; | ||
272 | else | ||
273 | { | ||
274 | const char *orig_str = __getopt_nonoption_flags; | ||
275 | int len = d->__nonoption_flags_max_len = strlen (orig_str); | ||
276 | if (d->__nonoption_flags_max_len < argc) | ||
277 | d->__nonoption_flags_max_len = argc; | ||
278 | __getopt_nonoption_flags = | ||
279 | (char *) malloc (d->__nonoption_flags_max_len); | ||
280 | if (__getopt_nonoption_flags == NULL) | ||
281 | d->__nonoption_flags_max_len = -1; | ||
282 | else | ||
283 | memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), | ||
284 | '\0', d->__nonoption_flags_max_len - len); | ||
285 | } | ||
286 | } | ||
287 | d->__nonoption_flags_len = d->__nonoption_flags_max_len; | ||
288 | } | ||
289 | else | ||
290 | d->__nonoption_flags_len = 0; | ||
291 | #endif | ||
292 | |||
293 | return optstring; | ||
294 | } | ||
295 | |||
296 | /* Scan elements of ARGV (whose length is ARGC) for option characters | ||
297 | given in OPTSTRING. | ||
298 | |||
299 | If an element of ARGV starts with '-', and is not exactly "-" or "--", | ||
300 | then it is an option element. The characters of this element | ||
301 | (aside from the initial '-') are option characters. If `getopt' | ||
302 | is called repeatedly, it returns successively each of the option characters | ||
303 | from each of the option elements. | ||
304 | |||
305 | If `getopt' finds another option character, it returns that character, | ||
306 | updating `optind' and `nextchar' so that the next call to `getopt' can | ||
307 | resume the scan with the following option character or ARGV-element. | ||
308 | |||
309 | If there are no more option characters, `getopt' returns -1. | ||
310 | Then `optind' is the index in ARGV of the first ARGV-element | ||
311 | that is not an option. (The ARGV-elements have been permuted | ||
312 | so that those that are not options now come last.) | ||
313 | |||
314 | OPTSTRING is a string containing the legitimate option characters. | ||
315 | If an option character is seen that is not listed in OPTSTRING, | ||
316 | return '?' after printing an error message. If you set `opterr' to | ||
317 | zero, the error message is suppressed but we still return '?'. | ||
318 | |||
319 | If a char in OPTSTRING is followed by a colon, that means it wants an arg, | ||
320 | so the following text in the same ARGV-element, or the text of the following | ||
321 | ARGV-element, is returned in `optarg'. Two colons mean an option that | ||
322 | wants an optional arg; if there is text in the current ARGV-element, | ||
323 | it is returned in `optarg', otherwise `optarg' is set to zero. | ||
324 | |||
325 | If OPTSTRING starts with `-' or `+', it requests different methods of | ||
326 | handling the non-option ARGV-elements. | ||
327 | See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. | ||
328 | |||
329 | Long-named options begin with `--' instead of `-'. | ||
330 | Their names may be abbreviated as long as the abbreviation is unique | ||
331 | or is an exact match for some defined option. If they have an | ||
332 | argument, it follows the option name in the same ARGV-element, separated | ||
333 | from the option name by a `=', or else the in next ARGV-element. | ||
334 | When `getopt' finds a long-named option, it returns 0 if that option's | ||
335 | `flag' field is nonzero, the value of the option's `val' field | ||
336 | if the `flag' field is zero. | ||
337 | |||
338 | LONGOPTS is a vector of `struct option' terminated by an | ||
339 | element containing a name which is zero. | ||
340 | |||
341 | LONGIND returns the index in LONGOPT of the long-named option found. | ||
342 | It is only valid when a long-named option has been found by the most | ||
343 | recent call. | ||
344 | |||
345 | If LONG_ONLY is nonzero, '-' as well as '--' can introduce | ||
346 | long-named options. | ||
347 | |||
348 | If POSIXLY_CORRECT is nonzero, behave as if the POSIXLY_CORRECT | ||
349 | environment variable were set. */ | ||
350 | |||
351 | int | ||
352 | _getopt_internal_r (int argc, char **argv, const char *optstring, | ||
353 | const struct option *longopts, int *longind, | ||
354 | int long_only, int posixly_correct, struct _getopt_data *d) | ||
355 | { | ||
356 | int print_errors = d->opterr; | ||
357 | if (optstring[0] == ':') | ||
358 | print_errors = 0; | ||
359 | |||
360 | if (argc < 1) | ||
361 | return -1; | ||
362 | |||
363 | d->optarg = NULL; | ||
364 | |||
365 | if (d->optind == 0 || !d->__initialized) | ||
366 | { | ||
367 | if (d->optind == 0) | ||
368 | d->optind = 1; /* Don't scan ARGV[0], the program name. */ | ||
369 | optstring = _getopt_initialize (argc, argv, optstring, | ||
370 | posixly_correct, d); | ||
371 | d->__initialized = 1; | ||
372 | } | ||
373 | |||
374 | /* Test whether ARGV[optind] points to a non-option argument. | ||
375 | Either it does not have option syntax, or there is an environment flag | ||
376 | from the shell indicating it is not an option. The later information | ||
377 | is only used when the used in the GNU libc. */ | ||
378 | #if defined _LIBC && defined USE_NONOPTION_FLAGS | ||
379 | # define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0' \ | ||
380 | || (d->optind < d->__nonoption_flags_len \ | ||
381 | && __getopt_nonoption_flags[d->optind] == '1')) | ||
382 | #else | ||
383 | # define NONOPTION_P (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0') | ||
384 | #endif | ||
385 | |||
386 | if (d->__nextchar == NULL || *d->__nextchar == '\0') | ||
387 | { | ||
388 | /* Advance to the next ARGV-element. */ | ||
389 | |||
390 | /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been | ||
391 | moved back by the user (who may also have changed the arguments). */ | ||
392 | if (d->__last_nonopt > d->optind) | ||
393 | d->__last_nonopt = d->optind; | ||
394 | if (d->__first_nonopt > d->optind) | ||
395 | d->__first_nonopt = d->optind; | ||
396 | |||
397 | if (d->__ordering == PERMUTE) | ||
398 | { | ||
399 | /* If we have just processed some options following some non-options, | ||
400 | exchange them so that the options come first. */ | ||
401 | |||
402 | if (d->__first_nonopt != d->__last_nonopt | ||
403 | && d->__last_nonopt != d->optind) | ||
404 | exchange ((char **) argv, d); | ||
405 | else if (d->__last_nonopt != d->optind) | ||
406 | d->__first_nonopt = d->optind; | ||
407 | |||
408 | /* Skip any additional non-options | ||
409 | and extend the range of non-options previously skipped. */ | ||
410 | |||
411 | while (d->optind < argc && NONOPTION_P) | ||
412 | d->optind++; | ||
413 | d->__last_nonopt = d->optind; | ||
414 | } | ||
415 | |||
416 | /* The special ARGV-element `--' means premature end of options. | ||
417 | Skip it like a null option, | ||
418 | then exchange with previous non-options as if it were an option, | ||
419 | then skip everything else like a non-option. */ | ||
420 | |||
421 | if (d->optind != argc && !strcmp (argv[d->optind], "--")) | ||
422 | { | ||
423 | d->optind++; | ||
424 | |||
425 | if (d->__first_nonopt != d->__last_nonopt | ||
426 | && d->__last_nonopt != d->optind) | ||
427 | exchange ((char **) argv, d); | ||
428 | else if (d->__first_nonopt == d->__last_nonopt) | ||
429 | d->__first_nonopt = d->optind; | ||
430 | d->__last_nonopt = argc; | ||
431 | |||
432 | d->optind = argc; | ||
433 | } | ||
434 | |||
435 | /* If we have done all the ARGV-elements, stop the scan | ||
436 | and back over any non-options that we skipped and permuted. */ | ||
437 | |||
438 | if (d->optind == argc) | ||
439 | { | ||
440 | /* Set the next-arg-index to point at the non-options | ||
441 | that we previously skipped, so the caller will digest them. */ | ||
442 | if (d->__first_nonopt != d->__last_nonopt) | ||
443 | d->optind = d->__first_nonopt; | ||
444 | return -1; | ||
445 | } | ||
446 | |||
447 | /* If we have come to a non-option and did not permute it, | ||
448 | either stop the scan or describe it to the caller and pass it by. */ | ||
449 | |||
450 | if (NONOPTION_P) | ||
451 | { | ||
452 | if (d->__ordering == REQUIRE_ORDER) | ||
453 | return -1; | ||
454 | d->optarg = argv[d->optind++]; | ||
455 | return 1; | ||
456 | } | ||
457 | |||
458 | /* We have found another option-ARGV-element. | ||
459 | Skip the initial punctuation. */ | ||
460 | |||
461 | d->__nextchar = (argv[d->optind] + 1 | ||
462 | + (longopts != NULL && argv[d->optind][1] == '-')); | ||
463 | } | ||
464 | |||
465 | /* Decode the current option-ARGV-element. */ | ||
466 | |||
467 | /* Check whether the ARGV-element is a long option. | ||
468 | |||
469 | If long_only and the ARGV-element has the form "-f", where f is | ||
470 | a valid short option, don't consider it an abbreviated form of | ||
471 | a long option that starts with f. Otherwise there would be no | ||
472 | way to give the -f short option. | ||
473 | |||
474 | On the other hand, if there's a long option "fubar" and | ||
475 | the ARGV-element is "-fu", do consider that an abbreviation of | ||
476 | the long option, just like "--fu", and not "-f" with arg "u". | ||
477 | |||
478 | This distinction seems to be the most useful approach. */ | ||
479 | |||
480 | if (longopts != NULL | ||
481 | && (argv[d->optind][1] == '-' | ||
482 | || (long_only && (argv[d->optind][2] | ||
483 | || !strchr (optstring, argv[d->optind][1]))))) | ||
484 | { | ||
485 | char *nameend; | ||
486 | const struct option *p; | ||
487 | const struct option *pfound = NULL; | ||
488 | int exact = 0; | ||
489 | int ambig = 0; | ||
490 | int indfound = -1; | ||
491 | int option_index; | ||
492 | |||
493 | for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++) | ||
494 | /* Do nothing. */ ; | ||
495 | |||
496 | /* Test all long options for either exact match | ||
497 | or abbreviated matches. */ | ||
498 | for (p = longopts, option_index = 0; p->name; p++, option_index++) | ||
499 | if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) | ||
500 | { | ||
501 | if ((unsigned int) (nameend - d->__nextchar) | ||
502 | == (unsigned int) strlen (p->name)) | ||
503 | { | ||
504 | /* Exact match found. */ | ||
505 | pfound = p; | ||
506 | indfound = option_index; | ||
507 | exact = 1; | ||
508 | break; | ||
509 | } | ||
510 | else if (pfound == NULL) | ||
511 | { | ||
512 | /* First nonexact match found. */ | ||
513 | pfound = p; | ||
514 | indfound = option_index; | ||
515 | } | ||
516 | else if (long_only | ||
517 | || pfound->has_arg != p->has_arg | ||
518 | || pfound->flag != p->flag | ||
519 | || pfound->val != p->val) | ||
520 | /* Second or later nonexact match found. */ | ||
521 | ambig = 1; | ||
522 | } | ||
523 | |||
524 | if (ambig && !exact) | ||
525 | { | ||
526 | if (print_errors) | ||
527 | { | ||
528 | #if defined _LIBC && defined USE_IN_LIBIO | ||
529 | char *buf; | ||
530 | |||
531 | if (__asprintf (&buf, _("%s: option `%s' is ambiguous\n"), | ||
532 | argv[0], argv[d->optind]) >= 0) | ||
533 | { | ||
534 | _IO_flockfile (stderr); | ||
535 | |||
536 | int old_flags2 = ((_IO_FILE *) stderr)->_flags2; | ||
537 | ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; | ||
538 | |||
539 | __fxprintf (NULL, "%s", buf); | ||
540 | |||
541 | ((_IO_FILE *) stderr)->_flags2 = old_flags2; | ||
542 | _IO_funlockfile (stderr); | ||
543 | |||
544 | free (buf); | ||
545 | } | ||
546 | #else | ||
547 | fprintf (stderr, _("%s: option `%s' is ambiguous\n"), | ||
548 | argv[0], argv[d->optind]); | ||
549 | #endif | ||
550 | } | ||
551 | d->__nextchar += strlen (d->__nextchar); | ||
552 | d->optind++; | ||
553 | d->optopt = 0; | ||
554 | return '?'; | ||
555 | } | ||
556 | |||
557 | if (pfound != NULL) | ||
558 | { | ||
559 | option_index = indfound; | ||
560 | d->optind++; | ||
561 | if (*nameend) | ||
562 | { | ||
563 | /* Don't test has_arg with >, because some C compilers don't | ||
564 | allow it to be used on enums. */ | ||
565 | if (pfound->has_arg) | ||
566 | d->optarg = nameend + 1; | ||
567 | else | ||
568 | { | ||
569 | if (print_errors) | ||
570 | { | ||
571 | #if defined _LIBC && defined USE_IN_LIBIO | ||
572 | char *buf; | ||
573 | int n; | ||
574 | #endif | ||
575 | |||
576 | if (argv[d->optind - 1][1] == '-') | ||
577 | { | ||
578 | /* --option */ | ||
579 | #if defined _LIBC && defined USE_IN_LIBIO | ||
580 | n = __asprintf (&buf, _("\ | ||
581 | %s: option `--%s' doesn't allow an argument\n"), | ||
582 | argv[0], pfound->name); | ||
583 | #else | ||
584 | fprintf (stderr, _("\ | ||
585 | %s: option `--%s' doesn't allow an argument\n"), | ||
586 | argv[0], pfound->name); | ||
587 | #endif | ||
588 | } | ||
589 | else | ||
590 | { | ||
591 | /* +option or -option */ | ||
592 | #if defined _LIBC && defined USE_IN_LIBIO | ||
593 | n = __asprintf (&buf, _("\ | ||
594 | %s: option `%c%s' doesn't allow an argument\n"), | ||
595 | argv[0], argv[d->optind - 1][0], | ||
596 | pfound->name); | ||
597 | #else | ||
598 | fprintf (stderr, _("\ | ||
599 | %s: option `%c%s' doesn't allow an argument\n"), | ||
600 | argv[0], argv[d->optind - 1][0], | ||
601 | pfound->name); | ||
602 | #endif | ||
603 | } | ||
604 | |||
605 | #if defined _LIBC && defined USE_IN_LIBIO | ||
606 | if (n >= 0) | ||
607 | { | ||
608 | _IO_flockfile (stderr); | ||
609 | |||
610 | int old_flags2 = ((_IO_FILE *) stderr)->_flags2; | ||
611 | ((_IO_FILE *) stderr)->_flags2 | ||
612 | |= _IO_FLAGS2_NOTCANCEL; | ||
613 | |||
614 | __fxprintf (NULL, "%s", buf); | ||
615 | |||
616 | ((_IO_FILE *) stderr)->_flags2 = old_flags2; | ||
617 | _IO_funlockfile (stderr); | ||
618 | |||
619 | free (buf); | ||
620 | } | ||
621 | #endif | ||
622 | } | ||
623 | |||
624 | d->__nextchar += strlen (d->__nextchar); | ||
625 | |||
626 | d->optopt = pfound->val; | ||
627 | return '?'; | ||
628 | } | ||
629 | } | ||
630 | else if (pfound->has_arg == 1) | ||
631 | { | ||
632 | if (d->optind < argc) | ||
633 | d->optarg = argv[d->optind++]; | ||
634 | else | ||
635 | { | ||
636 | if (print_errors) | ||
637 | { | ||
638 | #if defined _LIBC && defined USE_IN_LIBIO | ||
639 | char *buf; | ||
640 | |||
641 | if (__asprintf (&buf, _("\ | ||
642 | %s: option `%s' requires an argument\n"), | ||
643 | argv[0], argv[d->optind - 1]) >= 0) | ||
644 | { | ||
645 | _IO_flockfile (stderr); | ||
646 | |||
647 | int old_flags2 = ((_IO_FILE *) stderr)->_flags2; | ||
648 | ((_IO_FILE *) stderr)->_flags2 | ||
649 | |= _IO_FLAGS2_NOTCANCEL; | ||
650 | |||
651 | __fxprintf (NULL, "%s", buf); | ||
652 | |||
653 | ((_IO_FILE *) stderr)->_flags2 = old_flags2; | ||
654 | _IO_funlockfile (stderr); | ||
655 | |||
656 | free (buf); | ||
657 | } | ||
658 | #else | ||
659 | fprintf (stderr, | ||
660 | _("%s: option `%s' requires an argument\n"), | ||
661 | argv[0], argv[d->optind - 1]); | ||
662 | #endif | ||
663 | } | ||
664 | d->__nextchar += strlen (d->__nextchar); | ||
665 | d->optopt = pfound->val; | ||
666 | return optstring[0] == ':' ? ':' : '?'; | ||
667 | } | ||
668 | } | ||
669 | d->__nextchar += strlen (d->__nextchar); | ||
670 | if (longind != NULL) | ||
671 | *longind = option_index; | ||
672 | if (pfound->flag) | ||
673 | { | ||
674 | *(pfound->flag) = pfound->val; | ||
675 | return 0; | ||
676 | } | ||
677 | return pfound->val; | ||
678 | } | ||
679 | |||
680 | /* Can't find it as a long option. If this is not getopt_long_only, | ||
681 | or the option starts with '--' or is not a valid short | ||
682 | option, then it's an error. | ||
683 | Otherwise interpret it as a short option. */ | ||
684 | if (!long_only || argv[d->optind][1] == '-' | ||
685 | || strchr (optstring, *d->__nextchar) == NULL) | ||
686 | { | ||
687 | if (print_errors) | ||
688 | { | ||
689 | #if defined _LIBC && defined USE_IN_LIBIO | ||
690 | char *buf; | ||
691 | int n; | ||
692 | #endif | ||
693 | |||
694 | if (argv[d->optind][1] == '-') | ||
695 | { | ||
696 | /* --option */ | ||
697 | #if defined _LIBC && defined USE_IN_LIBIO | ||
698 | n = __asprintf (&buf, _("%s: unrecognized option `--%s'\n"), | ||
699 | argv[0], d->__nextchar); | ||
700 | #else | ||
701 | fprintf (stderr, _("%s: unrecognized option `--%s'\n"), | ||
702 | argv[0], d->__nextchar); | ||
703 | #endif | ||
704 | } | ||
705 | else | ||
706 | { | ||
707 | /* +option or -option */ | ||
708 | #if defined _LIBC && defined USE_IN_LIBIO | ||
709 | n = __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"), | ||
710 | argv[0], argv[d->optind][0], d->__nextchar); | ||
711 | #else | ||
712 | fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), | ||
713 | argv[0], argv[d->optind][0], d->__nextchar); | ||
714 | #endif | ||
715 | } | ||
716 | |||
717 | #if defined _LIBC && defined USE_IN_LIBIO | ||
718 | if (n >= 0) | ||
719 | { | ||
720 | _IO_flockfile (stderr); | ||
721 | |||
722 | int old_flags2 = ((_IO_FILE *) stderr)->_flags2; | ||
723 | ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; | ||
724 | |||
725 | __fxprintf (NULL, "%s", buf); | ||
726 | |||
727 | ((_IO_FILE *) stderr)->_flags2 = old_flags2; | ||
728 | _IO_funlockfile (stderr); | ||
729 | |||
730 | free (buf); | ||
731 | } | ||
732 | #endif | ||
733 | } | ||
734 | d->__nextchar = (char *) ""; | ||
735 | d->optind++; | ||
736 | d->optopt = 0; | ||
737 | return '?'; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | /* Look at and handle the next short option-character. */ | ||
742 | |||
743 | { | ||
744 | char c = *d->__nextchar++; | ||
745 | char *temp = strchr (optstring, c); | ||
746 | |||
747 | /* Increment `optind' when we start to process its last character. */ | ||
748 | if (*d->__nextchar == '\0') | ||
749 | ++d->optind; | ||
750 | |||
751 | if (temp == NULL || c == ':') | ||
752 | { | ||
753 | if (print_errors) | ||
754 | { | ||
755 | #if defined _LIBC && defined USE_IN_LIBIO | ||
756 | char *buf; | ||
757 | int n; | ||
758 | #endif | ||
759 | |||
760 | if (d->__posixly_correct) | ||
761 | { | ||
762 | /* 1003.2 specifies the format of this message. */ | ||
763 | #if defined _LIBC && defined USE_IN_LIBIO | ||
764 | n = __asprintf (&buf, _("%s: illegal option -- %c\n"), | ||
765 | argv[0], c); | ||
766 | #else | ||
767 | fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); | ||
768 | #endif | ||
769 | } | ||
770 | else | ||
771 | { | ||
772 | #if defined _LIBC && defined USE_IN_LIBIO | ||
773 | n = __asprintf (&buf, _("%s: invalid option -- %c\n"), | ||
774 | argv[0], c); | ||
775 | #else | ||
776 | fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); | ||
777 | #endif | ||
778 | } | ||
779 | |||
780 | #if defined _LIBC && defined USE_IN_LIBIO | ||
781 | if (n >= 0) | ||
782 | { | ||
783 | _IO_flockfile (stderr); | ||
784 | |||
785 | int old_flags2 = ((_IO_FILE *) stderr)->_flags2; | ||
786 | ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; | ||
787 | |||
788 | __fxprintf (NULL, "%s", buf); | ||
789 | |||
790 | ((_IO_FILE *) stderr)->_flags2 = old_flags2; | ||
791 | _IO_funlockfile (stderr); | ||
792 | |||
793 | free (buf); | ||
794 | } | ||
795 | #endif | ||
796 | } | ||
797 | d->optopt = c; | ||
798 | return '?'; | ||
799 | } | ||
800 | /* Convenience. Treat POSIX -W foo same as long option --foo */ | ||
801 | if (temp[0] == 'W' && temp[1] == ';') | ||
802 | { | ||
803 | char *nameend; | ||
804 | const struct option *p; | ||
805 | const struct option *pfound = NULL; | ||
806 | int exact = 0; | ||
807 | int ambig = 0; | ||
808 | int indfound = 0; | ||
809 | int option_index; | ||
810 | |||
811 | /* This is an option that requires an argument. */ | ||
812 | if (*d->__nextchar != '\0') | ||
813 | { | ||
814 | d->optarg = d->__nextchar; | ||
815 | /* If we end this ARGV-element by taking the rest as an arg, | ||
816 | we must advance to the next element now. */ | ||
817 | d->optind++; | ||
818 | } | ||
819 | else if (d->optind == argc) | ||
820 | { | ||
821 | if (print_errors) | ||
822 | { | ||
823 | /* 1003.2 specifies the format of this message. */ | ||
824 | #if defined _LIBC && defined USE_IN_LIBIO | ||
825 | char *buf; | ||
826 | |||
827 | if (__asprintf (&buf, | ||
828 | _("%s: option requires an argument -- %c\n"), | ||
829 | argv[0], c) >= 0) | ||
830 | { | ||
831 | _IO_flockfile (stderr); | ||
832 | |||
833 | int old_flags2 = ((_IO_FILE *) stderr)->_flags2; | ||
834 | ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; | ||
835 | |||
836 | __fxprintf (NULL, "%s", buf); | ||
837 | |||
838 | ((_IO_FILE *) stderr)->_flags2 = old_flags2; | ||
839 | _IO_funlockfile (stderr); | ||
840 | |||
841 | free (buf); | ||
842 | } | ||
843 | #else | ||
844 | fprintf (stderr, _("%s: option requires an argument -- %c\n"), | ||
845 | argv[0], c); | ||
846 | #endif | ||
847 | } | ||
848 | d->optopt = c; | ||
849 | if (optstring[0] == ':') | ||
850 | c = ':'; | ||
851 | else | ||
852 | c = '?'; | ||
853 | return c; | ||
854 | } | ||
855 | else | ||
856 | /* We already incremented `d->optind' once; | ||
857 | increment it again when taking next ARGV-elt as argument. */ | ||
858 | d->optarg = argv[d->optind++]; | ||
859 | |||
860 | /* optarg is now the argument, see if it's in the | ||
861 | table of longopts. */ | ||
862 | |||
863 | for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; | ||
864 | nameend++) | ||
865 | /* Do nothing. */ ; | ||
866 | |||
867 | /* Test all long options for either exact match | ||
868 | or abbreviated matches. */ | ||
869 | for (p = longopts, option_index = 0; p->name; p++, option_index++) | ||
870 | if (!strncmp (p->name, d->__nextchar, nameend - d->__nextchar)) | ||
871 | { | ||
872 | if ((unsigned int) (nameend - d->__nextchar) == strlen (p->name)) | ||
873 | { | ||
874 | /* Exact match found. */ | ||
875 | pfound = p; | ||
876 | indfound = option_index; | ||
877 | exact = 1; | ||
878 | break; | ||
879 | } | ||
880 | else if (pfound == NULL) | ||
881 | { | ||
882 | /* First nonexact match found. */ | ||
883 | pfound = p; | ||
884 | indfound = option_index; | ||
885 | } | ||
886 | else | ||
887 | /* Second or later nonexact match found. */ | ||
888 | ambig = 1; | ||
889 | } | ||
890 | if (ambig && !exact) | ||
891 | { | ||
892 | if (print_errors) | ||
893 | { | ||
894 | #if defined _LIBC && defined USE_IN_LIBIO | ||
895 | char *buf; | ||
896 | |||
897 | if (__asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"), | ||
898 | argv[0], argv[d->optind]) >= 0) | ||
899 | { | ||
900 | _IO_flockfile (stderr); | ||
901 | |||
902 | int old_flags2 = ((_IO_FILE *) stderr)->_flags2; | ||
903 | ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; | ||
904 | |||
905 | __fxprintf (NULL, "%s", buf); | ||
906 | |||
907 | ((_IO_FILE *) stderr)->_flags2 = old_flags2; | ||
908 | _IO_funlockfile (stderr); | ||
909 | |||
910 | free (buf); | ||
911 | } | ||
912 | #else | ||
913 | fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), | ||
914 | argv[0], argv[d->optind]); | ||
915 | #endif | ||
916 | } | ||
917 | d->__nextchar += strlen (d->__nextchar); | ||
918 | d->optind++; | ||
919 | return '?'; | ||
920 | } | ||
921 | if (pfound != NULL) | ||
922 | { | ||
923 | option_index = indfound; | ||
924 | if (*nameend) | ||
925 | { | ||
926 | /* Don't test has_arg with >, because some C compilers don't | ||
927 | allow it to be used on enums. */ | ||
928 | if (pfound->has_arg) | ||
929 | d->optarg = nameend + 1; | ||
930 | else | ||
931 | { | ||
932 | if (print_errors) | ||
933 | { | ||
934 | #if defined _LIBC && defined USE_IN_LIBIO | ||
935 | char *buf; | ||
936 | |||
937 | if (__asprintf (&buf, _("\ | ||
938 | %s: option `-W %s' doesn't allow an argument\n"), | ||
939 | argv[0], pfound->name) >= 0) | ||
940 | { | ||
941 | _IO_flockfile (stderr); | ||
942 | |||
943 | int old_flags2 = ((_IO_FILE *) stderr)->_flags2; | ||
944 | ((_IO_FILE *) stderr)->_flags2 | ||
945 | |= _IO_FLAGS2_NOTCANCEL; | ||
946 | |||
947 | __fxprintf (NULL, "%s", buf); | ||
948 | |||
949 | ((_IO_FILE *) stderr)->_flags2 = old_flags2; | ||
950 | _IO_funlockfile (stderr); | ||
951 | |||
952 | free (buf); | ||
953 | } | ||
954 | #else | ||
955 | fprintf (stderr, _("\ | ||
956 | %s: option `-W %s' doesn't allow an argument\n"), | ||
957 | argv[0], pfound->name); | ||
958 | #endif | ||
959 | } | ||
960 | |||
961 | d->__nextchar += strlen (d->__nextchar); | ||
962 | return '?'; | ||
963 | } | ||
964 | } | ||
965 | else if (pfound->has_arg == 1) | ||
966 | { | ||
967 | if (d->optind < argc) | ||
968 | d->optarg = argv[d->optind++]; | ||
969 | else | ||
970 | { | ||
971 | if (print_errors) | ||
972 | { | ||
973 | #if defined _LIBC && defined USE_IN_LIBIO | ||
974 | char *buf; | ||
975 | |||
976 | if (__asprintf (&buf, _("\ | ||
977 | %s: option `%s' requires an argument\n"), | ||
978 | argv[0], argv[d->optind - 1]) >= 0) | ||
979 | { | ||
980 | _IO_flockfile (stderr); | ||
981 | |||
982 | int old_flags2 = ((_IO_FILE *) stderr)->_flags2; | ||
983 | ((_IO_FILE *) stderr)->_flags2 | ||
984 | |= _IO_FLAGS2_NOTCANCEL; | ||
985 | |||
986 | __fxprintf (NULL, "%s", buf); | ||
987 | |||
988 | ((_IO_FILE *) stderr)->_flags2 = old_flags2; | ||
989 | _IO_funlockfile (stderr); | ||
990 | |||
991 | free (buf); | ||
992 | } | ||
993 | #else | ||
994 | fprintf (stderr, | ||
995 | _("%s: option `%s' requires an argument\n"), | ||
996 | argv[0], argv[d->optind - 1]); | ||
997 | #endif | ||
998 | } | ||
999 | d->__nextchar += strlen (d->__nextchar); | ||
1000 | return optstring[0] == ':' ? ':' : '?'; | ||
1001 | } | ||
1002 | } | ||
1003 | d->__nextchar += strlen (d->__nextchar); | ||
1004 | if (longind != NULL) | ||
1005 | *longind = option_index; | ||
1006 | if (pfound->flag) | ||
1007 | { | ||
1008 | *(pfound->flag) = pfound->val; | ||
1009 | return 0; | ||
1010 | } | ||
1011 | return pfound->val; | ||
1012 | } | ||
1013 | d->__nextchar = NULL; | ||
1014 | return 'W'; /* Let the application handle it. */ | ||
1015 | } | ||
1016 | if (temp[1] == ':') | ||
1017 | { | ||
1018 | if (temp[2] == ':') | ||
1019 | { | ||
1020 | /* This is an option that accepts an argument optionally. */ | ||
1021 | if (*d->__nextchar != '\0') | ||
1022 | { | ||
1023 | d->optarg = d->__nextchar; | ||
1024 | d->optind++; | ||
1025 | } | ||
1026 | else | ||
1027 | d->optarg = NULL; | ||
1028 | d->__nextchar = NULL; | ||
1029 | } | ||
1030 | else | ||
1031 | { | ||
1032 | /* This is an option that requires an argument. */ | ||
1033 | if (*d->__nextchar != '\0') | ||
1034 | { | ||
1035 | d->optarg = d->__nextchar; | ||
1036 | /* If we end this ARGV-element by taking the rest as an arg, | ||
1037 | we must advance to the next element now. */ | ||
1038 | d->optind++; | ||
1039 | } | ||
1040 | else if (d->optind == argc) | ||
1041 | { | ||
1042 | if (print_errors) | ||
1043 | { | ||
1044 | /* 1003.2 specifies the format of this message. */ | ||
1045 | #if defined _LIBC && defined USE_IN_LIBIO | ||
1046 | char *buf; | ||
1047 | |||
1048 | if (__asprintf (&buf, _("\ | ||
1049 | %s: option requires an argument -- %c\n"), | ||
1050 | argv[0], c) >= 0) | ||
1051 | { | ||
1052 | _IO_flockfile (stderr); | ||
1053 | |||
1054 | int old_flags2 = ((_IO_FILE *) stderr)->_flags2; | ||
1055 | ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL; | ||
1056 | |||
1057 | __fxprintf (NULL, "%s", buf); | ||
1058 | |||
1059 | ((_IO_FILE *) stderr)->_flags2 = old_flags2; | ||
1060 | _IO_funlockfile (stderr); | ||
1061 | |||
1062 | free (buf); | ||
1063 | } | ||
1064 | #else | ||
1065 | fprintf (stderr, | ||
1066 | _("%s: option requires an argument -- %c\n"), | ||
1067 | argv[0], c); | ||
1068 | #endif | ||
1069 | } | ||
1070 | d->optopt = c; | ||
1071 | if (optstring[0] == ':') | ||
1072 | c = ':'; | ||
1073 | else | ||
1074 | c = '?'; | ||
1075 | } | ||
1076 | else | ||
1077 | /* We already incremented `optind' once; | ||
1078 | increment it again when taking next ARGV-elt as argument. */ | ||
1079 | d->optarg = argv[d->optind++]; | ||
1080 | d->__nextchar = NULL; | ||
1081 | } | ||
1082 | } | ||
1083 | return c; | ||
1084 | } | ||
1085 | } | ||
1086 | |||
1087 | int | ||
1088 | _getopt_internal (int argc, char **argv, const char *optstring, | ||
1089 | const struct option *longopts, int *longind, | ||
1090 | int long_only, int posixly_correct) | ||
1091 | { | ||
1092 | int result; | ||
1093 | |||
1094 | getopt_data.optind = optind; | ||
1095 | getopt_data.opterr = opterr; | ||
1096 | |||
1097 | result = _getopt_internal_r (argc, argv, optstring, longopts, longind, | ||
1098 | long_only, posixly_correct, &getopt_data); | ||
1099 | |||
1100 | optind = getopt_data.optind; | ||
1101 | optarg = getopt_data.optarg; | ||
1102 | optopt = getopt_data.optopt; | ||
1103 | |||
1104 | return result; | ||
1105 | } | ||
1106 | |||
1107 | /* glibc gets a LSB-compliant getopt. | ||
1108 | Standalone applications get a POSIX-compliant getopt. */ | ||
1109 | #if _LIBC | ||
1110 | enum { POSIXLY_CORRECT = 0 }; | ||
1111 | #else | ||
1112 | enum { POSIXLY_CORRECT = 1 }; | ||
1113 | #endif | ||
1114 | |||
1115 | int | ||
1116 | getopt (int argc, char *const *argv, const char *optstring) | ||
1117 | { | ||
1118 | return _getopt_internal (argc, (char **) argv, optstring, NULL, NULL, 0, | ||
1119 | POSIXLY_CORRECT); | ||
1120 | } | ||
1121 | |||
1122 | |||
1123 | #ifdef TEST | ||
1124 | |||
1125 | /* Compile with -DTEST to make an executable for use in testing | ||
1126 | the above definition of `getopt'. */ | ||
1127 | |||
1128 | int | ||
1129 | main (int argc, char **argv) | ||
1130 | { | ||
1131 | int c; | ||
1132 | int digit_optind = 0; | ||
1133 | |||
1134 | while (1) | ||
1135 | { | ||
1136 | int this_option_optind = optind ? optind : 1; | ||
1137 | |||
1138 | c = getopt (argc, argv, "abc:d:0123456789"); | ||
1139 | if (c == -1) | ||
1140 | break; | ||
1141 | |||
1142 | switch (c) | ||
1143 | { | ||
1144 | case '0': | ||
1145 | case '1': | ||
1146 | case '2': | ||
1147 | case '3': | ||
1148 | case '4': | ||
1149 | case '5': | ||
1150 | case '6': | ||
1151 | case '7': | ||
1152 | case '8': | ||
1153 | case '9': | ||
1154 | if (digit_optind != 0 && digit_optind != this_option_optind) | ||
1155 | printf ("digits occur in two different argv-elements.\n"); | ||
1156 | digit_optind = this_option_optind; | ||
1157 | printf ("option %c\n", c); | ||
1158 | break; | ||
1159 | |||
1160 | case 'a': | ||
1161 | printf ("option a\n"); | ||
1162 | break; | ||
1163 | |||
1164 | case 'b': | ||
1165 | printf ("option b\n"); | ||
1166 | break; | ||
1167 | |||
1168 | case 'c': | ||
1169 | printf ("option c with value `%s'\n", optarg); | ||
1170 | break; | ||
1171 | |||
1172 | case '?': | ||
1173 | break; | ||
1174 | |||
1175 | default: | ||
1176 | printf ("?? getopt returned character code 0%o ??\n", c); | ||
1177 | } | ||
1178 | } | ||
1179 | |||
1180 | if (optind < argc) | ||
1181 | { | ||
1182 | printf ("non-option ARGV-elements: "); | ||
1183 | while (optind < argc) | ||
1184 | printf ("%s ", argv[optind++]); | ||
1185 | printf ("\n"); | ||
1186 | } | ||
1187 | |||
1188 | exit (0); | ||
1189 | } | ||
1190 | |||
1191 | #endif /* TEST */ | ||
diff --git a/gl/getopt1.c b/gl/getopt1.c new file mode 100644 index 00000000..cc0746ea --- /dev/null +++ b/gl/getopt1.c | |||
@@ -0,0 +1,171 @@ | |||
1 | /* getopt_long and getopt_long_only entry points for GNU getopt. | ||
2 | Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98,2004,2006 | ||
3 | Free Software Foundation, Inc. | ||
4 | This file is part of the GNU C Library. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License along | ||
17 | with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #ifdef _LIBC | ||
21 | # include <getopt.h> | ||
22 | #else | ||
23 | # include <config.h> | ||
24 | # include "getopt.h" | ||
25 | #endif | ||
26 | #include "getopt_int.h" | ||
27 | |||
28 | #include <stdio.h> | ||
29 | |||
30 | /* This needs to come after some library #include | ||
31 | to get __GNU_LIBRARY__ defined. */ | ||
32 | #ifdef __GNU_LIBRARY__ | ||
33 | #include <stdlib.h> | ||
34 | #endif | ||
35 | |||
36 | #ifndef NULL | ||
37 | #define NULL 0 | ||
38 | #endif | ||
39 | |||
40 | int | ||
41 | getopt_long (int argc, char *__getopt_argv_const *argv, const char *options, | ||
42 | const struct option *long_options, int *opt_index) | ||
43 | { | ||
44 | return _getopt_internal (argc, (char **) argv, options, long_options, | ||
45 | opt_index, 0, 0); | ||
46 | } | ||
47 | |||
48 | int | ||
49 | _getopt_long_r (int argc, char **argv, const char *options, | ||
50 | const struct option *long_options, int *opt_index, | ||
51 | struct _getopt_data *d) | ||
52 | { | ||
53 | return _getopt_internal_r (argc, argv, options, long_options, opt_index, | ||
54 | 0, 0, d); | ||
55 | } | ||
56 | |||
57 | /* Like getopt_long, but '-' as well as '--' can indicate a long option. | ||
58 | If an option that starts with '-' (not '--') doesn't match a long option, | ||
59 | but does match a short option, it is parsed as a short option | ||
60 | instead. */ | ||
61 | |||
62 | int | ||
63 | getopt_long_only (int argc, char *__getopt_argv_const *argv, | ||
64 | const char *options, | ||
65 | const struct option *long_options, int *opt_index) | ||
66 | { | ||
67 | return _getopt_internal (argc, (char **) argv, options, long_options, | ||
68 | opt_index, 1, 0); | ||
69 | } | ||
70 | |||
71 | int | ||
72 | _getopt_long_only_r (int argc, char **argv, const char *options, | ||
73 | const struct option *long_options, int *opt_index, | ||
74 | struct _getopt_data *d) | ||
75 | { | ||
76 | return _getopt_internal_r (argc, argv, options, long_options, opt_index, | ||
77 | 1, 0, d); | ||
78 | } | ||
79 | |||
80 | |||
81 | #ifdef TEST | ||
82 | |||
83 | #include <stdio.h> | ||
84 | |||
85 | int | ||
86 | main (int argc, char **argv) | ||
87 | { | ||
88 | int c; | ||
89 | int digit_optind = 0; | ||
90 | |||
91 | while (1) | ||
92 | { | ||
93 | int this_option_optind = optind ? optind : 1; | ||
94 | int option_index = 0; | ||
95 | static struct option long_options[] = | ||
96 | { | ||
97 | {"add", 1, 0, 0}, | ||
98 | {"append", 0, 0, 0}, | ||
99 | {"delete", 1, 0, 0}, | ||
100 | {"verbose", 0, 0, 0}, | ||
101 | {"create", 0, 0, 0}, | ||
102 | {"file", 1, 0, 0}, | ||
103 | {0, 0, 0, 0} | ||
104 | }; | ||
105 | |||
106 | c = getopt_long (argc, argv, "abc:d:0123456789", | ||
107 | long_options, &option_index); | ||
108 | if (c == -1) | ||
109 | break; | ||
110 | |||
111 | switch (c) | ||
112 | { | ||
113 | case 0: | ||
114 | printf ("option %s", long_options[option_index].name); | ||
115 | if (optarg) | ||
116 | printf (" with arg %s", optarg); | ||
117 | printf ("\n"); | ||
118 | break; | ||
119 | |||
120 | case '0': | ||
121 | case '1': | ||
122 | case '2': | ||
123 | case '3': | ||
124 | case '4': | ||
125 | case '5': | ||
126 | case '6': | ||
127 | case '7': | ||
128 | case '8': | ||
129 | case '9': | ||
130 | if (digit_optind != 0 && digit_optind != this_option_optind) | ||
131 | printf ("digits occur in two different argv-elements.\n"); | ||
132 | digit_optind = this_option_optind; | ||
133 | printf ("option %c\n", c); | ||
134 | break; | ||
135 | |||
136 | case 'a': | ||
137 | printf ("option a\n"); | ||
138 | break; | ||
139 | |||
140 | case 'b': | ||
141 | printf ("option b\n"); | ||
142 | break; | ||
143 | |||
144 | case 'c': | ||
145 | printf ("option c with value `%s'\n", optarg); | ||
146 | break; | ||
147 | |||
148 | case 'd': | ||
149 | printf ("option d with value `%s'\n", optarg); | ||
150 | break; | ||
151 | |||
152 | case '?': | ||
153 | break; | ||
154 | |||
155 | default: | ||
156 | printf ("?? getopt returned character code 0%o ??\n", c); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | if (optind < argc) | ||
161 | { | ||
162 | printf ("non-option ARGV-elements: "); | ||
163 | while (optind < argc) | ||
164 | printf ("%s ", argv[optind++]); | ||
165 | printf ("\n"); | ||
166 | } | ||
167 | |||
168 | exit (0); | ||
169 | } | ||
170 | |||
171 | #endif /* TEST */ | ||
diff --git a/gl/getopt_.h b/gl/getopt_.h new file mode 100644 index 00000000..27fce3dc --- /dev/null +++ b/gl/getopt_.h | |||
@@ -0,0 +1,226 @@ | |||
1 | /* Declarations for getopt. | ||
2 | Copyright (C) 1989-1994,1996-1999,2001,2003,2004,2005,2006 | ||
3 | Free Software Foundation, Inc. | ||
4 | This file is part of the GNU C Library. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License along | ||
17 | with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #ifndef _GETOPT_H | ||
21 | |||
22 | #ifndef __need_getopt | ||
23 | # define _GETOPT_H 1 | ||
24 | #endif | ||
25 | |||
26 | /* Standalone applications should #define __GETOPT_PREFIX to an | ||
27 | identifier that prefixes the external functions and variables | ||
28 | defined in this header. When this happens, include the | ||
29 | headers that might declare getopt so that they will not cause | ||
30 | confusion if included after this file. Then systematically rename | ||
31 | identifiers so that they do not collide with the system functions | ||
32 | and variables. Renaming avoids problems with some compilers and | ||
33 | linkers. */ | ||
34 | #if defined __GETOPT_PREFIX && !defined __need_getopt | ||
35 | # include <stdlib.h> | ||
36 | # include <stdio.h> | ||
37 | # include <unistd.h> | ||
38 | # undef __need_getopt | ||
39 | # undef getopt | ||
40 | # undef getopt_long | ||
41 | # undef getopt_long_only | ||
42 | # undef optarg | ||
43 | # undef opterr | ||
44 | # undef optind | ||
45 | # undef optopt | ||
46 | # define __GETOPT_CONCAT(x, y) x ## y | ||
47 | # define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y) | ||
48 | # define __GETOPT_ID(y) __GETOPT_XCONCAT (__GETOPT_PREFIX, y) | ||
49 | # define getopt __GETOPT_ID (getopt) | ||
50 | # define getopt_long __GETOPT_ID (getopt_long) | ||
51 | # define getopt_long_only __GETOPT_ID (getopt_long_only) | ||
52 | # define optarg __GETOPT_ID (optarg) | ||
53 | # define opterr __GETOPT_ID (opterr) | ||
54 | # define optind __GETOPT_ID (optind) | ||
55 | # define optopt __GETOPT_ID (optopt) | ||
56 | #endif | ||
57 | |||
58 | /* Standalone applications get correct prototypes for getopt_long and | ||
59 | getopt_long_only; they declare "char **argv". libc uses prototypes | ||
60 | with "char *const *argv" that are incorrect because getopt_long and | ||
61 | getopt_long_only can permute argv; this is required for backward | ||
62 | compatibility (e.g., for LSB 2.0.1). | ||
63 | |||
64 | This used to be `#if defined __GETOPT_PREFIX && !defined __need_getopt', | ||
65 | but it caused redefinition warnings if both unistd.h and getopt.h were | ||
66 | included, since unistd.h includes getopt.h having previously defined | ||
67 | __need_getopt. | ||
68 | |||
69 | The only place where __getopt_argv_const is used is in definitions | ||
70 | of getopt_long and getopt_long_only below, but these are visible | ||
71 | only if __need_getopt is not defined, so it is quite safe to rewrite | ||
72 | the conditional as follows: | ||
73 | */ | ||
74 | #if !defined __need_getopt | ||
75 | # if defined __GETOPT_PREFIX | ||
76 | # define __getopt_argv_const /* empty */ | ||
77 | # else | ||
78 | # define __getopt_argv_const const | ||
79 | # endif | ||
80 | #endif | ||
81 | |||
82 | /* If __GNU_LIBRARY__ is not already defined, either we are being used | ||
83 | standalone, or this is the first header included in the source file. | ||
84 | If we are being used with glibc, we need to include <features.h>, but | ||
85 | that does not exist if we are standalone. So: if __GNU_LIBRARY__ is | ||
86 | not defined, include <ctype.h>, which will pull in <features.h> for us | ||
87 | if it's from glibc. (Why ctype.h? It's guaranteed to exist and it | ||
88 | doesn't flood the namespace with stuff the way some other headers do.) */ | ||
89 | #if !defined __GNU_LIBRARY__ | ||
90 | # include <ctype.h> | ||
91 | #endif | ||
92 | |||
93 | #ifndef __THROW | ||
94 | # ifndef __GNUC_PREREQ | ||
95 | # define __GNUC_PREREQ(maj, min) (0) | ||
96 | # endif | ||
97 | # if defined __cplusplus && __GNUC_PREREQ (2,8) | ||
98 | # define __THROW throw () | ||
99 | # else | ||
100 | # define __THROW | ||
101 | # endif | ||
102 | #endif | ||
103 | |||
104 | #ifdef __cplusplus | ||
105 | extern "C" { | ||
106 | #endif | ||
107 | |||
108 | /* For communication from `getopt' to the caller. | ||
109 | When `getopt' finds an option that takes an argument, | ||
110 | the argument value is returned here. | ||
111 | Also, when `ordering' is RETURN_IN_ORDER, | ||
112 | each non-option ARGV-element is returned here. */ | ||
113 | |||
114 | extern char *optarg; | ||
115 | |||
116 | /* Index in ARGV of the next element to be scanned. | ||
117 | This is used for communication to and from the caller | ||
118 | and for communication between successive calls to `getopt'. | ||
119 | |||
120 | On entry to `getopt', zero means this is the first call; initialize. | ||
121 | |||
122 | When `getopt' returns -1, this is the index of the first of the | ||
123 | non-option elements that the caller should itself scan. | ||
124 | |||
125 | Otherwise, `optind' communicates from one call to the next | ||
126 | how much of ARGV has been scanned so far. */ | ||
127 | |||
128 | extern int optind; | ||
129 | |||
130 | /* Callers store zero here to inhibit the error message `getopt' prints | ||
131 | for unrecognized options. */ | ||
132 | |||
133 | extern int opterr; | ||
134 | |||
135 | /* Set to an option character which was unrecognized. */ | ||
136 | |||
137 | extern int optopt; | ||
138 | |||
139 | #ifndef __need_getopt | ||
140 | /* Describe the long-named options requested by the application. | ||
141 | The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector | ||
142 | of `struct option' terminated by an element containing a name which is | ||
143 | zero. | ||
144 | |||
145 | The field `has_arg' is: | ||
146 | no_argument (or 0) if the option does not take an argument, | ||
147 | required_argument (or 1) if the option requires an argument, | ||
148 | optional_argument (or 2) if the option takes an optional argument. | ||
149 | |||
150 | If the field `flag' is not NULL, it points to a variable that is set | ||
151 | to the value given in the field `val' when the option is found, but | ||
152 | left unchanged if the option is not found. | ||
153 | |||
154 | To have a long-named option do something other than set an `int' to | ||
155 | a compiled-in constant, such as set a value from `optarg', set the | ||
156 | option's `flag' field to zero and its `val' field to a nonzero | ||
157 | value (the equivalent single-letter option character, if there is | ||
158 | one). For long options that have a zero `flag' field, `getopt' | ||
159 | returns the contents of the `val' field. */ | ||
160 | |||
161 | struct option | ||
162 | { | ||
163 | const char *name; | ||
164 | /* has_arg can't be an enum because some compilers complain about | ||
165 | type mismatches in all the code that assumes it is an int. */ | ||
166 | int has_arg; | ||
167 | int *flag; | ||
168 | int val; | ||
169 | }; | ||
170 | |||
171 | /* Names for the values of the `has_arg' field of `struct option'. */ | ||
172 | |||
173 | # define no_argument 0 | ||
174 | # define required_argument 1 | ||
175 | # define optional_argument 2 | ||
176 | #endif /* need getopt */ | ||
177 | |||
178 | |||
179 | /* Get definitions and prototypes for functions to process the | ||
180 | arguments in ARGV (ARGC of them, minus the program name) for | ||
181 | options given in OPTS. | ||
182 | |||
183 | Return the option character from OPTS just read. Return -1 when | ||
184 | there are no more options. For unrecognized options, or options | ||
185 | missing arguments, `optopt' is set to the option letter, and '?' is | ||
186 | returned. | ||
187 | |||
188 | The OPTS string is a list of characters which are recognized option | ||
189 | letters, optionally followed by colons, specifying that that letter | ||
190 | takes an argument, to be placed in `optarg'. | ||
191 | |||
192 | If a letter in OPTS is followed by two colons, its argument is | ||
193 | optional. This behavior is specific to the GNU `getopt'. | ||
194 | |||
195 | The argument `--' causes premature termination of argument | ||
196 | scanning, explicitly telling `getopt' that there are no more | ||
197 | options. | ||
198 | |||
199 | If OPTS begins with `-', then non-option arguments are treated as | ||
200 | arguments to the option '\1'. This behavior is specific to the GNU | ||
201 | `getopt'. If OPTS begins with `+', or POSIXLY_CORRECT is set in | ||
202 | the environment, then do not permute arguments. */ | ||
203 | |||
204 | extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) | ||
205 | __THROW; | ||
206 | |||
207 | #ifndef __need_getopt | ||
208 | extern int getopt_long (int ___argc, char *__getopt_argv_const *___argv, | ||
209 | const char *__shortopts, | ||
210 | const struct option *__longopts, int *__longind) | ||
211 | __THROW; | ||
212 | extern int getopt_long_only (int ___argc, char *__getopt_argv_const *___argv, | ||
213 | const char *__shortopts, | ||
214 | const struct option *__longopts, int *__longind) | ||
215 | __THROW; | ||
216 | |||
217 | #endif | ||
218 | |||
219 | #ifdef __cplusplus | ||
220 | } | ||
221 | #endif | ||
222 | |||
223 | /* Make sure we later can get all the definitions and declarations. */ | ||
224 | #undef __need_getopt | ||
225 | |||
226 | #endif /* getopt.h */ | ||
diff --git a/gl/getopt_int.h b/gl/getopt_int.h new file mode 100644 index 00000000..401579fd --- /dev/null +++ b/gl/getopt_int.h | |||
@@ -0,0 +1,131 @@ | |||
1 | /* Internal declarations for getopt. | ||
2 | Copyright (C) 1989-1994,1996-1999,2001,2003,2004 | ||
3 | Free Software Foundation, Inc. | ||
4 | This file is part of the GNU C Library. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License along | ||
17 | with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #ifndef _GETOPT_INT_H | ||
21 | #define _GETOPT_INT_H 1 | ||
22 | |||
23 | extern int _getopt_internal (int ___argc, char **___argv, | ||
24 | const char *__shortopts, | ||
25 | const struct option *__longopts, int *__longind, | ||
26 | int __long_only, int __posixly_correct); | ||
27 | |||
28 | |||
29 | /* Reentrant versions which can handle parsing multiple argument | ||
30 | vectors at the same time. */ | ||
31 | |||
32 | /* Data type for reentrant functions. */ | ||
33 | struct _getopt_data | ||
34 | { | ||
35 | /* These have exactly the same meaning as the corresponding global | ||
36 | variables, except that they are used for the reentrant | ||
37 | versions of getopt. */ | ||
38 | int optind; | ||
39 | int opterr; | ||
40 | int optopt; | ||
41 | char *optarg; | ||
42 | |||
43 | /* Internal members. */ | ||
44 | |||
45 | /* True if the internal members have been initialized. */ | ||
46 | int __initialized; | ||
47 | |||
48 | /* The next char to be scanned in the option-element | ||
49 | in which the last option character we returned was found. | ||
50 | This allows us to pick up the scan where we left off. | ||
51 | |||
52 | If this is zero, or a null string, it means resume the scan | ||
53 | by advancing to the next ARGV-element. */ | ||
54 | char *__nextchar; | ||
55 | |||
56 | /* Describe how to deal with options that follow non-option ARGV-elements. | ||
57 | |||
58 | If the caller did not specify anything, | ||
59 | the default is REQUIRE_ORDER if the environment variable | ||
60 | POSIXLY_CORRECT is defined, PERMUTE otherwise. | ||
61 | |||
62 | REQUIRE_ORDER means don't recognize them as options; | ||
63 | stop option processing when the first non-option is seen. | ||
64 | This is what Unix does. | ||
65 | This mode of operation is selected by either setting the environment | ||
66 | variable POSIXLY_CORRECT, or using `+' as the first character | ||
67 | of the list of option characters, or by calling getopt. | ||
68 | |||
69 | PERMUTE is the default. We permute the contents of ARGV as we | ||
70 | scan, so that eventually all the non-options are at the end. | ||
71 | This allows options to be given in any order, even with programs | ||
72 | that were not written to expect this. | ||
73 | |||
74 | RETURN_IN_ORDER is an option available to programs that were | ||
75 | written to expect options and other ARGV-elements in any order | ||
76 | and that care about the ordering of the two. We describe each | ||
77 | non-option ARGV-element as if it were the argument of an option | ||
78 | with character code 1. Using `-' as the first character of the | ||
79 | list of option characters selects this mode of operation. | ||
80 | |||
81 | The special argument `--' forces an end of option-scanning regardless | ||
82 | of the value of `ordering'. In the case of RETURN_IN_ORDER, only | ||
83 | `--' can cause `getopt' to return -1 with `optind' != ARGC. */ | ||
84 | |||
85 | enum | ||
86 | { | ||
87 | REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER | ||
88 | } __ordering; | ||
89 | |||
90 | /* If the POSIXLY_CORRECT environment variable is set | ||
91 | or getopt was called. */ | ||
92 | int __posixly_correct; | ||
93 | |||
94 | |||
95 | /* Handle permutation of arguments. */ | ||
96 | |||
97 | /* Describe the part of ARGV that contains non-options that have | ||
98 | been skipped. `first_nonopt' is the index in ARGV of the first | ||
99 | of them; `last_nonopt' is the index after the last of them. */ | ||
100 | |||
101 | int __first_nonopt; | ||
102 | int __last_nonopt; | ||
103 | |||
104 | #if defined _LIBC && defined USE_NONOPTION_FLAGS | ||
105 | int __nonoption_flags_max_len; | ||
106 | int __nonoption_flags_len; | ||
107 | # endif | ||
108 | }; | ||
109 | |||
110 | /* The initializer is necessary to set OPTIND and OPTERR to their | ||
111 | default values and to clear the initialization flag. */ | ||
112 | #define _GETOPT_DATA_INITIALIZER { 1, 1 } | ||
113 | |||
114 | extern int _getopt_internal_r (int ___argc, char **___argv, | ||
115 | const char *__shortopts, | ||
116 | const struct option *__longopts, int *__longind, | ||
117 | int __long_only, int __posixly_correct, | ||
118 | struct _getopt_data *__data); | ||
119 | |||
120 | extern int _getopt_long_r (int ___argc, char **___argv, | ||
121 | const char *__shortopts, | ||
122 | const struct option *__longopts, int *__longind, | ||
123 | struct _getopt_data *__data); | ||
124 | |||
125 | extern int _getopt_long_only_r (int ___argc, char **___argv, | ||
126 | const char *__shortopts, | ||
127 | const struct option *__longopts, | ||
128 | int *__longind, | ||
129 | struct _getopt_data *__data); | ||
130 | |||
131 | #endif /* getopt_int.h */ | ||
diff --git a/gl/gettext.h b/gl/gettext.h new file mode 100644 index 00000000..9d76ec9a --- /dev/null +++ b/gl/gettext.h | |||
@@ -0,0 +1,270 @@ | |||
1 | /* Convenience header for conditional use of GNU <libintl.h>. | ||
2 | Copyright (C) 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _LIBGETTEXT_H | ||
19 | #define _LIBGETTEXT_H 1 | ||
20 | |||
21 | /* NLS can be disabled through the configure --disable-nls option. */ | ||
22 | #if ENABLE_NLS | ||
23 | |||
24 | /* Get declarations of GNU message catalog functions. */ | ||
25 | # include <libintl.h> | ||
26 | |||
27 | /* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by | ||
28 | the gettext() and ngettext() macros. This is an alternative to calling | ||
29 | textdomain(), and is useful for libraries. */ | ||
30 | # ifdef DEFAULT_TEXT_DOMAIN | ||
31 | # undef gettext | ||
32 | # define gettext(Msgid) \ | ||
33 | dgettext (DEFAULT_TEXT_DOMAIN, Msgid) | ||
34 | # undef ngettext | ||
35 | # define ngettext(Msgid1, Msgid2, N) \ | ||
36 | dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) | ||
37 | # endif | ||
38 | |||
39 | #else | ||
40 | |||
41 | /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which | ||
42 | chokes if dcgettext is defined as a macro. So include it now, to make | ||
43 | later inclusions of <locale.h> a NOP. We don't include <libintl.h> | ||
44 | as well because people using "gettext.h" will not include <libintl.h>, | ||
45 | and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> | ||
46 | is OK. */ | ||
47 | #if defined(__sun) | ||
48 | # include <locale.h> | ||
49 | #endif | ||
50 | |||
51 | /* Many header files from the libstdc++ coming with g++ 3.3 or newer include | ||
52 | <libintl.h>, which chokes if dcgettext is defined as a macro. So include | ||
53 | it now, to make later inclusions of <libintl.h> a NOP. */ | ||
54 | #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) | ||
55 | # include <cstdlib> | ||
56 | # if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H | ||
57 | # include <libintl.h> | ||
58 | # endif | ||
59 | #endif | ||
60 | |||
61 | /* Disabled NLS. | ||
62 | The casts to 'const char *' serve the purpose of producing warnings | ||
63 | for invalid uses of the value returned from these functions. | ||
64 | On pre-ANSI systems without 'const', the config.h file is supposed to | ||
65 | contain "#define const". */ | ||
66 | # define gettext(Msgid) ((const char *) (Msgid)) | ||
67 | # define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) | ||
68 | # define dcgettext(Domainname, Msgid, Category) \ | ||
69 | ((void) (Category), dgettext (Domainname, Msgid)) | ||
70 | # define ngettext(Msgid1, Msgid2, N) \ | ||
71 | ((N) == 1 \ | ||
72 | ? ((void) (Msgid2), (const char *) (Msgid1)) \ | ||
73 | : ((void) (Msgid1), (const char *) (Msgid2))) | ||
74 | # define dngettext(Domainname, Msgid1, Msgid2, N) \ | ||
75 | ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) | ||
76 | # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ | ||
77 | ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N)) | ||
78 | # define textdomain(Domainname) ((const char *) (Domainname)) | ||
79 | # define bindtextdomain(Domainname, Dirname) \ | ||
80 | ((void) (Domainname), (const char *) (Dirname)) | ||
81 | # define bind_textdomain_codeset(Domainname, Codeset) \ | ||
82 | ((void) (Domainname), (const char *) (Codeset)) | ||
83 | |||
84 | #endif | ||
85 | |||
86 | /* A pseudo function call that serves as a marker for the automated | ||
87 | extraction of messages, but does not call gettext(). The run-time | ||
88 | translation is done at a different place in the code. | ||
89 | The argument, String, should be a literal string. Concatenated strings | ||
90 | and other string expressions won't work. | ||
91 | The macro's expansion is not parenthesized, so that it is suitable as | ||
92 | initializer for static 'char[]' or 'const char[]' variables. */ | ||
93 | #define gettext_noop(String) String | ||
94 | |||
95 | /* The separator between msgctxt and msgid in a .mo file. */ | ||
96 | #define GETTEXT_CONTEXT_GLUE "\004" | ||
97 | |||
98 | /* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a | ||
99 | MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be | ||
100 | short and rarely need to change. | ||
101 | The letter 'p' stands for 'particular' or 'special'. */ | ||
102 | #ifdef DEFAULT_TEXT_DOMAIN | ||
103 | # define pgettext(Msgctxt, Msgid) \ | ||
104 | pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) | ||
105 | #else | ||
106 | # define pgettext(Msgctxt, Msgid) \ | ||
107 | pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) | ||
108 | #endif | ||
109 | #define dpgettext(Domainname, Msgctxt, Msgid) \ | ||
110 | pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) | ||
111 | #define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ | ||
112 | pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) | ||
113 | #ifdef DEFAULT_TEXT_DOMAIN | ||
114 | # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ | ||
115 | npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) | ||
116 | #else | ||
117 | # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ | ||
118 | npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) | ||
119 | #endif | ||
120 | #define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ | ||
121 | npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) | ||
122 | #define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ | ||
123 | npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) | ||
124 | |||
125 | #ifdef __GNUC__ | ||
126 | __inline | ||
127 | #else | ||
128 | #ifdef __cplusplus | ||
129 | inline | ||
130 | #endif | ||
131 | #endif | ||
132 | static const char * | ||
133 | pgettext_aux (const char *domain, | ||
134 | const char *msg_ctxt_id, const char *msgid, | ||
135 | int category) | ||
136 | { | ||
137 | const char *translation = dcgettext (domain, msg_ctxt_id, category); | ||
138 | if (translation == msg_ctxt_id) | ||
139 | return msgid; | ||
140 | else | ||
141 | return translation; | ||
142 | } | ||
143 | |||
144 | #ifdef __GNUC__ | ||
145 | __inline | ||
146 | #else | ||
147 | #ifdef __cplusplus | ||
148 | inline | ||
149 | #endif | ||
150 | #endif | ||
151 | static const char * | ||
152 | npgettext_aux (const char *domain, | ||
153 | const char *msg_ctxt_id, const char *msgid, | ||
154 | const char *msgid_plural, unsigned long int n, | ||
155 | int category) | ||
156 | { | ||
157 | const char *translation = | ||
158 | dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); | ||
159 | if (translation == msg_ctxt_id || translation == msgid_plural) | ||
160 | return (n == 1 ? msgid : msgid_plural); | ||
161 | else | ||
162 | return translation; | ||
163 | } | ||
164 | |||
165 | /* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID | ||
166 | can be arbitrary expressions. But for string literals these macros are | ||
167 | less efficient than those above. */ | ||
168 | |||
169 | #include <string.h> | ||
170 | |||
171 | #define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ | ||
172 | (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \ | ||
173 | /* || __STDC_VERSION__ >= 199901L */ ) | ||
174 | |||
175 | #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS | ||
176 | #include <stdlib.h> | ||
177 | #endif | ||
178 | |||
179 | #define pgettext_expr(Msgctxt, Msgid) \ | ||
180 | dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) | ||
181 | #define dpgettext_expr(Domainname, Msgctxt, Msgid) \ | ||
182 | dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) | ||
183 | |||
184 | #ifdef __GNUC__ | ||
185 | __inline | ||
186 | #else | ||
187 | #ifdef __cplusplus | ||
188 | inline | ||
189 | #endif | ||
190 | #endif | ||
191 | static const char * | ||
192 | dcpgettext_expr (const char *domain, | ||
193 | const char *msgctxt, const char *msgid, | ||
194 | int category) | ||
195 | { | ||
196 | size_t msgctxt_len = strlen (msgctxt) + 1; | ||
197 | size_t msgid_len = strlen (msgid) + 1; | ||
198 | const char *translation; | ||
199 | #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS | ||
200 | char msg_ctxt_id[msgctxt_len + msgid_len]; | ||
201 | #else | ||
202 | char buf[1024]; | ||
203 | char *msg_ctxt_id = | ||
204 | (msgctxt_len + msgid_len <= sizeof (buf) | ||
205 | ? buf | ||
206 | : (char *) malloc (msgctxt_len + msgid_len)); | ||
207 | if (msg_ctxt_id != NULL) | ||
208 | #endif | ||
209 | { | ||
210 | memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); | ||
211 | msg_ctxt_id[msgctxt_len - 1] = '\004'; | ||
212 | memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); | ||
213 | translation = dcgettext (domain, msg_ctxt_id, category); | ||
214 | #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS | ||
215 | if (msg_ctxt_id != buf) | ||
216 | free (msg_ctxt_id); | ||
217 | #endif | ||
218 | if (translation != msg_ctxt_id) | ||
219 | return translation; | ||
220 | } | ||
221 | return msgid; | ||
222 | } | ||
223 | |||
224 | #define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ | ||
225 | dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) | ||
226 | #define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ | ||
227 | dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) | ||
228 | |||
229 | #ifdef __GNUC__ | ||
230 | __inline | ||
231 | #else | ||
232 | #ifdef __cplusplus | ||
233 | inline | ||
234 | #endif | ||
235 | #endif | ||
236 | static const char * | ||
237 | dcnpgettext_expr (const char *domain, | ||
238 | const char *msgctxt, const char *msgid, | ||
239 | const char *msgid_plural, unsigned long int n, | ||
240 | int category) | ||
241 | { | ||
242 | size_t msgctxt_len = strlen (msgctxt) + 1; | ||
243 | size_t msgid_len = strlen (msgid) + 1; | ||
244 | const char *translation; | ||
245 | #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS | ||
246 | char msg_ctxt_id[msgctxt_len + msgid_len]; | ||
247 | #else | ||
248 | char buf[1024]; | ||
249 | char *msg_ctxt_id = | ||
250 | (msgctxt_len + msgid_len <= sizeof (buf) | ||
251 | ? buf | ||
252 | : (char *) malloc (msgctxt_len + msgid_len)); | ||
253 | if (msg_ctxt_id != NULL) | ||
254 | #endif | ||
255 | { | ||
256 | memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); | ||
257 | msg_ctxt_id[msgctxt_len - 1] = '\004'; | ||
258 | memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); | ||
259 | translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); | ||
260 | #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS | ||
261 | if (msg_ctxt_id != buf) | ||
262 | free (msg_ctxt_id); | ||
263 | #endif | ||
264 | if (!(translation == msg_ctxt_id || translation == msgid_plural)) | ||
265 | return translation; | ||
266 | } | ||
267 | return (n == 1 ? msgid : msgid_plural); | ||
268 | } | ||
269 | |||
270 | #endif /* _LIBGETTEXT_H */ | ||
diff --git a/gl/inet_ntop.c b/gl/inet_ntop.c new file mode 100644 index 00000000..537b59fa --- /dev/null +++ b/gl/inet_ntop.c | |||
@@ -0,0 +1,238 @@ | |||
1 | /* inet_ntop.c -- convert IPv4 and IPv6 addresses from binary to text form | ||
2 | |||
3 | Copyright (C) 2005, 2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* | ||
20 | * Copyright (c) 1996-1999 by Internet Software Consortium. | ||
21 | * | ||
22 | * Permission to use, copy, modify, and distribute this software for any | ||
23 | * purpose with or without fee is hereby granted, provided that the above | ||
24 | * copyright notice and this permission notice appear in all copies. | ||
25 | * | ||
26 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS | ||
27 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | ||
28 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE | ||
29 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | ||
30 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | ||
31 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | ||
32 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | ||
33 | * SOFTWARE. | ||
34 | */ | ||
35 | |||
36 | #include <config.h> | ||
37 | |||
38 | /* Specification. */ | ||
39 | #include "inet_ntop.h" | ||
40 | |||
41 | #include <stdio.h> | ||
42 | #include <string.h> | ||
43 | #include <errno.h> | ||
44 | |||
45 | #ifndef EAFNOSUPPORT | ||
46 | # define EAFNOSUPPORT EINVAL | ||
47 | #endif | ||
48 | |||
49 | #define NS_IN6ADDRSZ 16 | ||
50 | #define NS_INT16SZ 2 | ||
51 | |||
52 | /* | ||
53 | * WARNING: Don't even consider trying to compile this on a system where | ||
54 | * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. | ||
55 | */ | ||
56 | typedef int verify_int_size[2 * sizeof (int) - 7]; | ||
57 | |||
58 | static const char *inet_ntop4 (const unsigned char *src, char *dst, socklen_t size); | ||
59 | #if HAVE_IPV6 | ||
60 | static const char *inet_ntop6 (const unsigned char *src, char *dst, socklen_t size); | ||
61 | #endif | ||
62 | |||
63 | |||
64 | /* char * | ||
65 | * inet_ntop(af, src, dst, size) | ||
66 | * convert a network format address to presentation format. | ||
67 | * return: | ||
68 | * pointer to presentation format address (`dst'), or NULL (see errno). | ||
69 | * author: | ||
70 | * Paul Vixie, 1996. | ||
71 | */ | ||
72 | const char * | ||
73 | inet_ntop (int af, const void *restrict src, | ||
74 | char *restrict dst, socklen_t cnt) | ||
75 | { | ||
76 | switch (af) | ||
77 | { | ||
78 | #if HAVE_IPV4 | ||
79 | case AF_INET: | ||
80 | return (inet_ntop4 (src, dst, cnt)); | ||
81 | #endif | ||
82 | |||
83 | #if HAVE_IPV6 | ||
84 | case AF_INET6: | ||
85 | return (inet_ntop6 (src, dst, cnt)); | ||
86 | #endif | ||
87 | |||
88 | default: | ||
89 | errno = EAFNOSUPPORT; | ||
90 | return (NULL); | ||
91 | } | ||
92 | /* NOTREACHED */ | ||
93 | } | ||
94 | |||
95 | /* const char * | ||
96 | * inet_ntop4(src, dst, size) | ||
97 | * format an IPv4 address | ||
98 | * return: | ||
99 | * `dst' (as a const) | ||
100 | * notes: | ||
101 | * (1) uses no statics | ||
102 | * (2) takes a u_char* not an in_addr as input | ||
103 | * author: | ||
104 | * Paul Vixie, 1996. | ||
105 | */ | ||
106 | static const char * | ||
107 | inet_ntop4 (const unsigned char *src, char *dst, socklen_t size) | ||
108 | { | ||
109 | char tmp[sizeof "255.255.255.255"]; | ||
110 | int len; | ||
111 | |||
112 | len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]); | ||
113 | if (len < 0) | ||
114 | return NULL; | ||
115 | |||
116 | if (len > size) | ||
117 | { | ||
118 | errno = ENOSPC; | ||
119 | return NULL; | ||
120 | } | ||
121 | |||
122 | return strcpy (dst, tmp); | ||
123 | } | ||
124 | |||
125 | #if HAVE_IPV6 | ||
126 | |||
127 | /* const char * | ||
128 | * inet_ntop6(src, dst, size) | ||
129 | * convert IPv6 binary address into presentation (printable) format | ||
130 | * author: | ||
131 | * Paul Vixie, 1996. | ||
132 | */ | ||
133 | static const char * | ||
134 | inet_ntop6 (const unsigned char *src, char *dst, socklen_t size) | ||
135 | { | ||
136 | /* | ||
137 | * Note that int32_t and int16_t need only be "at least" large enough | ||
138 | * to contain a value of the specified size. On some systems, like | ||
139 | * Crays, there is no such thing as an integer variable with 16 bits. | ||
140 | * Keep this in mind if you think this function should have been coded | ||
141 | * to use pointer overlays. All the world's not a VAX. | ||
142 | */ | ||
143 | char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; | ||
144 | struct | ||
145 | { | ||
146 | int base, len; | ||
147 | } best, cur; | ||
148 | unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; | ||
149 | int i; | ||
150 | |||
151 | /* | ||
152 | * Preprocess: | ||
153 | * Copy the input (bytewise) array into a wordwise array. | ||
154 | * Find the longest run of 0x00's in src[] for :: shorthanding. | ||
155 | */ | ||
156 | memset (words, '\0', sizeof words); | ||
157 | for (i = 0; i < NS_IN6ADDRSZ; i += 2) | ||
158 | words[i / 2] = (src[i] << 8) | src[i + 1]; | ||
159 | best.base = -1; | ||
160 | cur.base = -1; | ||
161 | for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) | ||
162 | { | ||
163 | if (words[i] == 0) | ||
164 | { | ||
165 | if (cur.base == -1) | ||
166 | cur.base = i, cur.len = 1; | ||
167 | else | ||
168 | cur.len++; | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | if (cur.base != -1) | ||
173 | { | ||
174 | if (best.base == -1 || cur.len > best.len) | ||
175 | best = cur; | ||
176 | cur.base = -1; | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | if (cur.base != -1) | ||
181 | { | ||
182 | if (best.base == -1 || cur.len > best.len) | ||
183 | best = cur; | ||
184 | } | ||
185 | if (best.base != -1 && best.len < 2) | ||
186 | best.base = -1; | ||
187 | |||
188 | /* | ||
189 | * Format the result. | ||
190 | */ | ||
191 | tp = tmp; | ||
192 | for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) | ||
193 | { | ||
194 | /* Are we inside the best run of 0x00's? */ | ||
195 | if (best.base != -1 && i >= best.base && i < (best.base + best.len)) | ||
196 | { | ||
197 | if (i == best.base) | ||
198 | *tp++ = ':'; | ||
199 | continue; | ||
200 | } | ||
201 | /* Are we following an initial run of 0x00s or any real hex? */ | ||
202 | if (i != 0) | ||
203 | *tp++ = ':'; | ||
204 | /* Is this address an encapsulated IPv4? */ | ||
205 | if (i == 6 && best.base == 0 && | ||
206 | (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) | ||
207 | { | ||
208 | if (!inet_ntop4 (src + 12, tp, sizeof tmp - (tp - tmp))) | ||
209 | return (NULL); | ||
210 | tp += strlen (tp); | ||
211 | break; | ||
212 | } | ||
213 | { | ||
214 | int len = sprintf (tp, "%x", words[i]); | ||
215 | if (len < 0) | ||
216 | return NULL; | ||
217 | tp += len; | ||
218 | } | ||
219 | } | ||
220 | /* Was it a trailing run of 0x00's? */ | ||
221 | if (best.base != -1 && (best.base + best.len) == | ||
222 | (NS_IN6ADDRSZ / NS_INT16SZ)) | ||
223 | *tp++ = ':'; | ||
224 | *tp++ = '\0'; | ||
225 | |||
226 | /* | ||
227 | * Check for overflow, copy, and we're done. | ||
228 | */ | ||
229 | if ((socklen_t) (tp - tmp) > size) | ||
230 | { | ||
231 | errno = ENOSPC; | ||
232 | return NULL; | ||
233 | } | ||
234 | |||
235 | return strcpy (dst, tmp); | ||
236 | } | ||
237 | |||
238 | #endif | ||
diff --git a/gl/inet_ntop.h b/gl/inet_ntop.h new file mode 100644 index 00000000..bd1e085a --- /dev/null +++ b/gl/inet_ntop.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* Convert internet address from internal to printable, presentable format. | ||
2 | Copyright (C) 2005, 2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #include <sys/types.h> | ||
19 | #include <sys/socket.h> | ||
20 | #include <netinet/in.h> | ||
21 | #include <arpa/inet.h> | ||
22 | |||
23 | /* Converts an internet address from internal format to a printable, | ||
24 | presentable format. | ||
25 | AF is an internet address family, such as AF_INET or AF_INET6. | ||
26 | SRC points to a 'struct in_addr' (for AF_INET) or 'struct in6_addr' | ||
27 | (for AF_INET6). | ||
28 | DST points to a buffer having room for CNT bytes. | ||
29 | The printable representation of the address (in numeric form, not | ||
30 | surrounded by [...], no reverse DNS is done) is placed in DST, and | ||
31 | DST is returned. If an error occurs, the return value is NULL and | ||
32 | errno is set. If CNT bytes are not sufficient to hold the result, | ||
33 | the return value is NULL and errno is set to ENOSPC. A good value | ||
34 | for CNT is 46. | ||
35 | |||
36 | For more details, see the POSIX:2001 specification | ||
37 | <http://www.opengroup.org/susv3xsh/inet_ntop.html>. */ | ||
38 | |||
39 | #if !HAVE_DECL_INET_NTOP | ||
40 | extern const char *inet_ntop (int af, const void *restrict src, | ||
41 | char *restrict dst, socklen_t cnt); | ||
42 | #endif | ||
diff --git a/gl/intprops.h b/gl/intprops.h new file mode 100644 index 00000000..34f971cb --- /dev/null +++ b/gl/intprops.h | |||
@@ -0,0 +1,78 @@ | |||
1 | /* intprops.h -- properties of integer types | ||
2 | |||
3 | Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Paul Eggert. */ | ||
20 | |||
21 | #include <limits.h> | ||
22 | |||
23 | /* The extra casts in the following macros work around compiler bugs, | ||
24 | e.g., in Cray C 5.0.3.0. */ | ||
25 | |||
26 | /* True if the arithmetic type T is an integer type. bool counts as | ||
27 | an integer. */ | ||
28 | #define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) | ||
29 | |||
30 | /* True if negative values of the signed integer type T use two's | ||
31 | complement, ones' complement, or signed magnitude representation, | ||
32 | respectively. Much GNU code assumes two's complement, but some | ||
33 | people like to be portable to all possible C hosts. */ | ||
34 | #define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1) | ||
35 | #define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0) | ||
36 | #define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1) | ||
37 | |||
38 | /* True if the arithmetic type T is signed. */ | ||
39 | #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) | ||
40 | |||
41 | /* The maximum and minimum values for the integer type T. These | ||
42 | macros have undefined behavior if T is signed and has padding bits. | ||
43 | If this is a problem for you, please let us know how to fix it for | ||
44 | your host. */ | ||
45 | #define TYPE_MINIMUM(t) \ | ||
46 | ((t) (! TYPE_SIGNED (t) \ | ||
47 | ? (t) 0 \ | ||
48 | : TYPE_SIGNED_MAGNITUDE (t) \ | ||
49 | ? ~ (t) 0 \ | ||
50 | : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))) | ||
51 | #define TYPE_MAXIMUM(t) \ | ||
52 | ((t) (! TYPE_SIGNED (t) \ | ||
53 | ? (t) -1 \ | ||
54 | : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))) | ||
55 | |||
56 | /* Return zero if T can be determined to be an unsigned type. | ||
57 | Otherwise, return 1. | ||
58 | When compiling with GCC, INT_STRLEN_BOUND uses this macro to obtain a | ||
59 | tighter bound. Otherwise, it overestimates the true bound by one byte | ||
60 | when applied to unsigned types of size 2, 4, 16, ... bytes. | ||
61 | The symbol signed_type_or_expr__ is private to this header file. */ | ||
62 | #if __GNUC__ >= 2 | ||
63 | # define signed_type_or_expr__(t) TYPE_SIGNED (__typeof__ (t)) | ||
64 | #else | ||
65 | # define signed_type_or_expr__(t) 1 | ||
66 | #endif | ||
67 | |||
68 | /* Bound on length of the string representing an integer type or expression T. | ||
69 | Subtract 1 for the sign bit if T is signed; log10 (2.0) < 146/485; | ||
70 | add 1 for integer division truncation; add 1 more for a minus sign | ||
71 | if needed. */ | ||
72 | #define INT_STRLEN_BOUND(t) \ | ||
73 | ((sizeof (t) * CHAR_BIT - signed_type_or_expr__ (t)) * 146 / 485 \ | ||
74 | + signed_type_or_expr__ (t) + 1) | ||
75 | |||
76 | /* Bound on buffer size needed to represent an integer type or expression T, | ||
77 | including the terminating null. */ | ||
78 | #define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) | ||
diff --git a/gl/m4/absolute-header.m4 b/gl/m4/absolute-header.m4 new file mode 100644 index 00000000..c649df08 --- /dev/null +++ b/gl/m4/absolute-header.m4 | |||
@@ -0,0 +1,44 @@ | |||
1 | # absolute-header.m4 serial 6 | ||
2 | dnl Copyright (C) 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Derek Price. | ||
8 | |||
9 | # gl_ABSOLUTE_HEADER(HEADER1 HEADER2 ...) | ||
10 | # --------------------------------------- | ||
11 | # Find the absolute name of a header file, assuming the header exists. | ||
12 | # If the header were sys/inttypes.h, this macro would define | ||
13 | # ABSOLUTE_SYS_INTTYPES_H to the `""' quoted absolute name of sys/inttypes.h | ||
14 | # in config.h | ||
15 | # (e.g. `#define ABSOLUTE_SYS_INTTYPES_H "///usr/include/sys/inttypes.h"'). | ||
16 | # The three "///" are to pacify Sun C 5.8, which otherwise would say | ||
17 | # "warning: #include of /usr/include/... may be non-portable". | ||
18 | # Use `""', not `<>', so that the /// cannot be confused with a C99 comment. | ||
19 | AC_DEFUN([gl_ABSOLUTE_HEADER], | ||
20 | [AC_LANG_PREPROC_REQUIRE()dnl | ||
21 | AC_FOREACH([gl_HEADER_NAME], [$1], | ||
22 | [AS_VAR_PUSHDEF([gl_absolute_header], | ||
23 | [gl_cv_absolute_]m4_quote(m4_defn([gl_HEADER_NAME])))dnl | ||
24 | AC_CACHE_CHECK([absolute name of <]m4_quote(m4_defn([gl_HEADER_NAME]))[>], | ||
25 | m4_quote(m4_defn([gl_absolute_header])), | ||
26 | [AS_VAR_PUSHDEF([ac_header_exists], | ||
27 | [ac_cv_header_]m4_quote(m4_defn([gl_HEADER_NAME])))dnl | ||
28 | AC_CHECK_HEADERS_ONCE(m4_quote(m4_defn([gl_HEADER_NAME])))dnl | ||
29 | if test AS_VAR_GET(ac_header_exists) = yes; then | ||
30 | AC_LANG_CONFTEST([AC_LANG_SOURCE([[#include <]]m4_dquote(m4_defn([gl_HEADER_NAME]))[[>]])]) | ||
31 | dnl eval is necessary to expand ac_cpp. | ||
32 | dnl Ultrix and Pyramid sh refuse to redirect output of eval, so use subshell. | ||
33 | AS_VAR_SET(gl_absolute_header, | ||
34 | [`(eval "$ac_cpp conftest.$ac_ext") 2>&AS_MESSAGE_LOG_FD | | ||
35 | sed -n '\#/]m4_quote(m4_defn([gl_HEADER_NAME]))[#{s#.*"\(.*/]m4_quote(m4_defn([gl_HEADER_NAME]))[\)".*#\1#;s#^/[^/]#//&#;p;q;}'`]) | ||
36 | fi | ||
37 | AS_VAR_POPDEF([ac_header_exists])dnl | ||
38 | ])dnl | ||
39 | AC_DEFINE_UNQUOTED(AS_TR_CPP([ABSOLUTE_]m4_quote(m4_defn([gl_HEADER_NAME]))), | ||
40 | ["AS_VAR_GET(gl_absolute_header)"], | ||
41 | [Define this to an absolute name of <]m4_quote(m4_defn([gl_HEADER_NAME]))[>.]) | ||
42 | AS_VAR_POPDEF([gl_absolute_header])dnl | ||
43 | ])dnl | ||
44 | ])# gl_ABSOLUTE_HEADER | ||
diff --git a/gl/m4/alloca.m4 b/gl/m4/alloca.m4 new file mode 100644 index 00000000..eb62e0e7 --- /dev/null +++ b/gl/m4/alloca.m4 | |||
@@ -0,0 +1,50 @@ | |||
1 | # alloca.m4 serial 7 | ||
2 | dnl Copyright (C) 2002-2004, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FUNC_ALLOCA], | ||
8 | [ | ||
9 | dnl Work around a bug of AC_EGREP_CPP in autoconf-2.57. | ||
10 | AC_REQUIRE([AC_PROG_CPP]) | ||
11 | AC_REQUIRE([AC_PROG_EGREP]) | ||
12 | |||
13 | AC_REQUIRE([AC_FUNC_ALLOCA]) | ||
14 | if test $ac_cv_func_alloca_works = no; then | ||
15 | gl_PREREQ_ALLOCA | ||
16 | fi | ||
17 | |||
18 | # Define an additional variable used in the Makefile substitution. | ||
19 | if test $ac_cv_working_alloca_h = yes; then | ||
20 | AC_CACHE_CHECK([for alloca as a compiler built-in], [gl_cv_rpl_alloca], [ | ||
21 | AC_EGREP_CPP([Need own alloca], [ | ||
22 | #if defined __GNUC__ || defined _AIX || defined _MSC_VER | ||
23 | Need own alloca | ||
24 | #endif | ||
25 | ], [gl_cv_rpl_alloca=yes], [gl_cv_rpl_alloca=no]) | ||
26 | ]) | ||
27 | if test $gl_cv_rpl_alloca = yes; then | ||
28 | dnl OK, alloca can be implemented through a compiler built-in. | ||
29 | AC_DEFINE([HAVE_ALLOCA], 1, | ||
30 | [Define to 1 if you have 'alloca' after including <alloca.h>, | ||
31 | a header that may be supplied by this distribution.]) | ||
32 | ALLOCA_H=alloca.h | ||
33 | else | ||
34 | dnl alloca exists as a library function, i.e. it is slow and probably | ||
35 | dnl a memory leak. Don't define HAVE_ALLOCA in this case. | ||
36 | ALLOCA_H= | ||
37 | fi | ||
38 | else | ||
39 | ALLOCA_H=alloca.h | ||
40 | fi | ||
41 | AC_SUBST([ALLOCA_H]) | ||
42 | |||
43 | AC_DEFINE(HAVE_ALLOCA_H, 1, | ||
44 | [Define HAVE_ALLOCA_H for backward compatibility with older code | ||
45 | that includes <alloca.h> only if HAVE_ALLOCA_H is defined.]) | ||
46 | ]) | ||
47 | |||
48 | # Prerequisites of lib/alloca.c. | ||
49 | # STACK_DIRECTION is already handled by AC_FUNC_ALLOCA. | ||
50 | AC_DEFUN([gl_PREREQ_ALLOCA], [:]) | ||
diff --git a/gl/m4/arpa_inet_h.m4 b/gl/m4/arpa_inet_h.m4 new file mode 100644 index 00000000..d01d0984 --- /dev/null +++ b/gl/m4/arpa_inet_h.m4 | |||
@@ -0,0 +1,18 @@ | |||
1 | # arpa_inet_h.m4 serial 1 | ||
2 | dnl Copyright (C) 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl Written by Simon Josefsson | ||
8 | |||
9 | AC_DEFUN([gl_HEADER_ARPA_INET], | ||
10 | [ | ||
11 | AC_CHECK_HEADERS_ONCE([arpa/inet.h]) | ||
12 | if test $ac_cv_header_arpa_inet_h = yes; then | ||
13 | ARPA_INET_H='' | ||
14 | else | ||
15 | ARPA_INET_H='arpa/inet.h' | ||
16 | fi | ||
17 | AC_SUBST(ARPA_INET_H) | ||
18 | ]) | ||
diff --git a/gl/m4/c-strtod.m4 b/gl/m4/c-strtod.m4 new file mode 100644 index 00000000..7f206c71 --- /dev/null +++ b/gl/m4/c-strtod.m4 | |||
@@ -0,0 +1,53 @@ | |||
1 | # c-strtod.m4 serial 9 | ||
2 | |||
3 | # Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. | ||
4 | # This file is free software; the Free Software Foundation | ||
5 | # gives unlimited permission to copy and/or distribute it, | ||
6 | # with or without modifications, as long as this notice is preserved. | ||
7 | |||
8 | # Written by Paul Eggert. | ||
9 | |||
10 | AC_DEFUN([gl_C99_STRTOLD], | ||
11 | [ | ||
12 | AC_CACHE_CHECK([whether strtold conforms to C99], | ||
13 | [gl_cv_func_c99_strtold], | ||
14 | [AC_LINK_IFELSE( | ||
15 | [AC_LANG_PROGRAM( | ||
16 | [[/* On HP-UX before 11.23, strtold returns a struct instead of | ||
17 | long double. Reject implementations like that, by requiring | ||
18 | compatibility with the C99 prototype. */ | ||
19 | #include <stdlib.h> | ||
20 | static long double (*p) (char const *, char **) = strtold; | ||
21 | static long double | ||
22 | test (char const *nptr, char **endptr) | ||
23 | { | ||
24 | long double r; | ||
25 | r = strtold (nptr, endptr); | ||
26 | return r; | ||
27 | }]], | ||
28 | [[return test ("1.0", NULL) != 1 || p ("1.0", NULL) != 1;]])], | ||
29 | [gl_cv_func_c99_strtold=yes], | ||
30 | [gl_cv_func_c99_strtold=no])]) | ||
31 | if test $gl_cv_func_c99_strtold = yes; then | ||
32 | AC_DEFINE([HAVE_C99_STRTOLD], 1, [Define to 1 if strtold conforms to C99.]) | ||
33 | fi | ||
34 | ]) | ||
35 | |||
36 | AC_DEFUN([gl_C_STRTOD], | ||
37 | [ | ||
38 | AC_LIBOBJ([c-strtod]) | ||
39 | |||
40 | dnl Prerequisites of lib/c-strtod.c. | ||
41 | AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) | ||
42 | : | ||
43 | ]) | ||
44 | |||
45 | AC_DEFUN([gl_C_STRTOLD], | ||
46 | [ | ||
47 | AC_LIBOBJ([c-strtold]) | ||
48 | |||
49 | dnl Prerequisites of lib/c-strtold.c. | ||
50 | AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) | ||
51 | AC_REQUIRE([gl_C99_STRTOLD]) | ||
52 | : | ||
53 | ]) | ||
diff --git a/gl/m4/cloexec.m4 b/gl/m4/cloexec.m4 new file mode 100644 index 00000000..4c4e26a1 --- /dev/null +++ b/gl/m4/cloexec.m4 | |||
@@ -0,0 +1,10 @@ | |||
1 | #serial 6 | ||
2 | dnl Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_CLOEXEC], | ||
8 | [ | ||
9 | AC_LIBOBJ([cloexec]) | ||
10 | ]) | ||
diff --git a/gl/m4/codeset.m4 b/gl/m4/codeset.m4 new file mode 100644 index 00000000..223955b4 --- /dev/null +++ b/gl/m4/codeset.m4 | |||
@@ -0,0 +1,21 @@ | |||
1 | # codeset.m4 serial 2 (gettext-0.16) | ||
2 | dnl Copyright (C) 2000-2002, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | |||
9 | AC_DEFUN([AM_LANGINFO_CODESET], | ||
10 | [ | ||
11 | AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, | ||
12 | [AC_TRY_LINK([#include <langinfo.h>], | ||
13 | [char* cs = nl_langinfo(CODESET); return !cs;], | ||
14 | am_cv_langinfo_codeset=yes, | ||
15 | am_cv_langinfo_codeset=no) | ||
16 | ]) | ||
17 | if test $am_cv_langinfo_codeset = yes; then | ||
18 | AC_DEFINE(HAVE_LANGINFO_CODESET, 1, | ||
19 | [Define if you have <langinfo.h> and nl_langinfo(CODESET).]) | ||
20 | fi | ||
21 | ]) | ||
diff --git a/gl/m4/dirname.m4 b/gl/m4/dirname.m4 new file mode 100644 index 00000000..e35da965 --- /dev/null +++ b/gl/m4/dirname.m4 | |||
@@ -0,0 +1,18 @@ | |||
1 | #serial 7 -*- autoconf -*- | ||
2 | dnl Copyright (C) 2002-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_DIRNAME], | ||
8 | [ | ||
9 | AC_LIBOBJ([basename]) | ||
10 | AC_LIBOBJ([dirname]) | ||
11 | AC_LIBOBJ([stripslash]) | ||
12 | |||
13 | dnl Prerequisites of lib/dirname.h. | ||
14 | AC_REQUIRE([gl_AC_DOS]) | ||
15 | AC_REQUIRE([gl_DOUBLE_SLASH_ROOT]) | ||
16 | |||
17 | dnl No prerequisites of lib/basename.c, lib/dirname.c, lib/stripslash.c. | ||
18 | ]) | ||
diff --git a/gl/m4/dos.m4 b/gl/m4/dos.m4 new file mode 100644 index 00000000..dd59571c --- /dev/null +++ b/gl/m4/dos.m4 | |||
@@ -0,0 +1,71 @@ | |||
1 | #serial 10 -*- autoconf -*- | ||
2 | |||
3 | # Define some macros required for proper operation of code in lib/*.c | ||
4 | # on MSDOS/Windows systems. | ||
5 | |||
6 | # Copyright (C) 2000, 2001, 2004, 2005, 2006 Free Software Foundation, Inc. | ||
7 | # This file is free software; the Free Software Foundation | ||
8 | # gives unlimited permission to copy and/or distribute it, | ||
9 | # with or without modifications, as long as this notice is preserved. | ||
10 | |||
11 | # From Jim Meyering. | ||
12 | |||
13 | AC_DEFUN([gl_AC_DOS], | ||
14 | [ | ||
15 | AC_CACHE_CHECK([whether system is Windows or MSDOS], [ac_cv_win_or_dos], | ||
16 | [ | ||
17 | AC_TRY_COMPILE([], | ||
18 | [#if !defined _WIN32 && !defined __WIN32__ && !defined __MSDOS__ && !defined __CYGWIN__ | ||
19 | neither MSDOS nor Windows | ||
20 | #endif], | ||
21 | [ac_cv_win_or_dos=yes], | ||
22 | [ac_cv_win_or_dos=no]) | ||
23 | ]) | ||
24 | |||
25 | if test x"$ac_cv_win_or_dos" = xyes; then | ||
26 | ac_fs_accepts_drive_letter_prefix=1 | ||
27 | ac_fs_backslash_is_file_name_separator=1 | ||
28 | AC_CACHE_CHECK([whether drive letter can start relative path], | ||
29 | [ac_cv_drive_letter_can_be_relative], | ||
30 | [ | ||
31 | AC_TRY_COMPILE([], | ||
32 | [#if defined __CYGWIN__ | ||
33 | drive letters are always absolute | ||
34 | #endif], | ||
35 | [ac_cv_drive_letter_can_be_relative=yes], | ||
36 | [ac_cv_drive_letter_can_be_relative=no]) | ||
37 | ]) | ||
38 | if test x"$ac_cv_drive_letter_can_be_relative" = xyes; then | ||
39 | ac_fs_drive_letter_can_be_relative=1 | ||
40 | else | ||
41 | ac_fs_drive_letter_can_be_relative=0 | ||
42 | fi | ||
43 | else | ||
44 | ac_fs_accepts_drive_letter_prefix=0 | ||
45 | ac_fs_backslash_is_file_name_separator=0 | ||
46 | ac_fs_drive_letter_can_be_relative=0 | ||
47 | fi | ||
48 | |||
49 | AC_DEFINE_UNQUOTED([FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX], | ||
50 | $ac_fs_accepts_drive_letter_prefix, | ||
51 | [Define on systems for which file names may have a so-called | ||
52 | `drive letter' prefix, define this to compute the length of that | ||
53 | prefix, including the colon.]) | ||
54 | |||
55 | AH_VERBATIM(ISSLASH, | ||
56 | [#if FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR | ||
57 | # define ISSLASH(C) ((C) == '/' || (C) == '\\') | ||
58 | #else | ||
59 | # define ISSLASH(C) ((C) == '/') | ||
60 | #endif]) | ||
61 | |||
62 | AC_DEFINE_UNQUOTED([FILE_SYSTEM_BACKSLASH_IS_FILE_NAME_SEPARATOR], | ||
63 | $ac_fs_backslash_is_file_name_separator, | ||
64 | [Define if the backslash character may also serve as a file name | ||
65 | component separator.]) | ||
66 | |||
67 | AC_DEFINE_UNQUOTED([FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE], | ||
68 | $ac_fs_drive_letter_can_be_relative, | ||
69 | [Define if a drive letter prefix denotes a relative path if it is | ||
70 | not followed by a file name component separator.]) | ||
71 | ]) | ||
diff --git a/gl/m4/double-slash-root.m4 b/gl/m4/double-slash-root.m4 new file mode 100644 index 00000000..69d60d01 --- /dev/null +++ b/gl/m4/double-slash-root.m4 | |||
@@ -0,0 +1,38 @@ | |||
1 | # double-slash-root.m4 serial 2 -*- Autoconf -*- | ||
2 | dnl Copyright (C) 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_DOUBLE_SLASH_ROOT], | ||
8 | [ | ||
9 | AC_REQUIRE([AC_CANONICAL_HOST]) | ||
10 | AC_CACHE_CHECK([whether // is distinct from /], [gl_cv_double_slash_root], | ||
11 | [ if test x"$cross_compiling" = xyes ; then | ||
12 | # When cross-compiling, there is no way to tell whether // is special | ||
13 | # short of a list of hosts. However, the only known hosts to date | ||
14 | # that have a distinct // are Apollo DomainOS (too old to port to), | ||
15 | # Cygwin, and z/OS. If anyone knows of another system for which // has | ||
16 | # special semantics and is distinct from /, please report it to | ||
17 | # <bug-gnulib@gnu.org>. | ||
18 | case $host in | ||
19 | *-cygwin | i370-ibm-openedition) | ||
20 | gl_cv_double_slash_root=yes ;; | ||
21 | *) | ||
22 | # Be optimistic and assume that / and // are the same when we | ||
23 | # don't know. | ||
24 | gl_cv_double_slash_root='unknown, assuming no' ;; | ||
25 | esac | ||
26 | else | ||
27 | set x `ls -di / //` | ||
28 | if test $[2] = $[4] && wc //dev/null >/dev/null 2>&1; then | ||
29 | gl_cv_double_slash_root=no | ||
30 | else | ||
31 | gl_cv_double_slash_root=yes | ||
32 | fi | ||
33 | fi]) | ||
34 | if test "$gl_cv_double_slash_root" = yes; then | ||
35 | AC_DEFINE([DOUBLE_SLASH_IS_DISTINCT_ROOT], 1, | ||
36 | [Define to 1 if // is a file system root distinct from /.]) | ||
37 | fi | ||
38 | ]) | ||
diff --git a/gl/m4/eoverflow.m4 b/gl/m4/eoverflow.m4 new file mode 100644 index 00000000..3bffd10e --- /dev/null +++ b/gl/m4/eoverflow.m4 | |||
@@ -0,0 +1,70 @@ | |||
1 | # eoverflow.m4 serial 2 | ||
2 | dnl Copyright (C) 2004, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | |||
9 | # The EOVERFLOW errno value ought to be defined in <errno.h>, according to | ||
10 | # POSIX. But some systems (like AIX 3) don't define it, and some systems | ||
11 | # (like OSF/1) define it when _XOPEN_SOURCE_EXTENDED is defined. | ||
12 | |||
13 | # Define EOVERFLOW as a C macro and as a substituted macro in such a way that | ||
14 | # 1. on all systems, after inclusion of <errno.h>, EOVERFLOW is usable, | ||
15 | # 2. on systems where EOVERFLOW is defined elsewhere, we use the same numeric | ||
16 | # value. | ||
17 | |||
18 | AC_DEFUN([gl_EOVERFLOW], | ||
19 | [ | ||
20 | AC_REQUIRE([AC_PROG_CC])dnl | ||
21 | |||
22 | AC_CACHE_CHECK([for EOVERFLOW], ac_cv_decl_EOVERFLOW, [ | ||
23 | AC_EGREP_CPP(yes,[ | ||
24 | #include <errno.h> | ||
25 | #ifdef EOVERFLOW | ||
26 | yes | ||
27 | #endif | ||
28 | ], have_eoverflow=1) | ||
29 | if test -n "$have_eoverflow"; then | ||
30 | dnl EOVERFLOW exists in <errno.h>. Don't need to define EOVERFLOW ourselves. | ||
31 | ac_cv_decl_EOVERFLOW=yes | ||
32 | else | ||
33 | AC_EGREP_CPP(yes,[ | ||
34 | #define _XOPEN_SOURCE_EXTENDED 1 | ||
35 | #include <errno.h> | ||
36 | #ifdef EOVERFLOW | ||
37 | yes | ||
38 | #endif | ||
39 | ], have_eoverflow=1) | ||
40 | if test -n "$have_eoverflow"; then | ||
41 | dnl EOVERFLOW exists but is hidden. | ||
42 | dnl Define it to the same value. | ||
43 | AC_COMPUTE_INT([ac_cv_decl_EOVERFLOW], [EOVERFLOW], [ | ||
44 | #define _XOPEN_SOURCE_EXTENDED 1 | ||
45 | #include <errno.h> | ||
46 | /* The following two lines are a workaround against an autoconf-2.52 bug. */ | ||
47 | #include <stdio.h> | ||
48 | #include <stdlib.h> | ||
49 | ]) | ||
50 | else | ||
51 | dnl EOVERFLOW isn't defined by the system. Define EOVERFLOW ourselves, but | ||
52 | dnl don't define it as EINVAL, because snprintf() callers want to | ||
53 | dnl distinguish EINVAL and EOVERFLOW. | ||
54 | ac_cv_decl_EOVERFLOW=E2BIG | ||
55 | fi | ||
56 | fi | ||
57 | ]) | ||
58 | if test "$ac_cv_decl_EOVERFLOW" != yes; then | ||
59 | AC_DEFINE_UNQUOTED([EOVERFLOW], [$ac_cv_decl_EOVERFLOW], | ||
60 | [Define as good substitute value for EOVERFLOW.]) | ||
61 | EOVERFLOW="$ac_cv_decl_EOVERFLOW" | ||
62 | AC_SUBST(EOVERFLOW) | ||
63 | fi | ||
64 | ]) | ||
65 | |||
66 | dnl Autoconf >= 2.61 has AC_COMPUTE_INT built-in. | ||
67 | dnl Remove this when we can assume autoconf >= 2.61. | ||
68 | m4_ifdef([AC_COMPUTE_INT], [], [ | ||
69 | AC_DEFUN([AC_COMPUTE_INT], [_AC_COMPUTE_INT([$2],[$1],[$3],[$4])]) | ||
70 | ]) | ||
diff --git a/gl/m4/error.m4 b/gl/m4/error.m4 new file mode 100644 index 00000000..7c7746e2 --- /dev/null +++ b/gl/m4/error.m4 | |||
@@ -0,0 +1,22 @@ | |||
1 | #serial 11 | ||
2 | |||
3 | # Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004 Free Software | ||
4 | # Foundation, Inc. | ||
5 | # | ||
6 | # This file is free software; the Free Software Foundation | ||
7 | # gives unlimited permission to copy and/or distribute it, | ||
8 | # with or without modifications, as long as this notice is preserved. | ||
9 | |||
10 | AC_DEFUN([gl_ERROR], | ||
11 | [ | ||
12 | AC_FUNC_ERROR_AT_LINE | ||
13 | dnl Note: AC_FUNC_ERROR_AT_LINE does AC_LIBSOURCES([error.h, error.c]). | ||
14 | gl_PREREQ_ERROR | ||
15 | ]) | ||
16 | |||
17 | # Prerequisites of lib/error.c. | ||
18 | AC_DEFUN([gl_PREREQ_ERROR], | ||
19 | [ | ||
20 | AC_REQUIRE([AC_FUNC_STRERROR_R]) | ||
21 | : | ||
22 | ]) | ||
diff --git a/gl/m4/exitfail.m4 b/gl/m4/exitfail.m4 new file mode 100644 index 00000000..b7a691e5 --- /dev/null +++ b/gl/m4/exitfail.m4 | |||
@@ -0,0 +1,13 @@ | |||
1 | # exitfail.m4 serial 6 | ||
2 | dnl Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_EXITFAIL], | ||
8 | [ | ||
9 | AC_LIBOBJ([exitfail]) | ||
10 | |||
11 | dnl No prerequisites of lib/exitfail.c. | ||
12 | : | ||
13 | ]) | ||
diff --git a/gl/m4/extensions.m4 b/gl/m4/extensions.m4 new file mode 100644 index 00000000..143a9e54 --- /dev/null +++ b/gl/m4/extensions.m4 | |||
@@ -0,0 +1,58 @@ | |||
1 | # serial 4 -*- Autoconf -*- | ||
2 | # Enable extensions on systems that normally disable them. | ||
3 | |||
4 | # Copyright (C) 2003, 2006 Free Software Foundation, Inc. | ||
5 | # This file is free software; the Free Software Foundation | ||
6 | # gives unlimited permission to copy and/or distribute it, | ||
7 | # with or without modifications, as long as this notice is preserved. | ||
8 | |||
9 | # This definition of AC_USE_SYSTEM_EXTENSIONS is stolen from CVS | ||
10 | # Autoconf. Perhaps we can remove this once we can assume Autoconf | ||
11 | # 2.61 or later everywhere, but since CVS Autoconf mutates rapidly | ||
12 | # enough in this area it's likely we'll need to redefine | ||
13 | # AC_USE_SYSTEM_EXTENSIONS for quite some time. | ||
14 | |||
15 | # AC_USE_SYSTEM_EXTENSIONS | ||
16 | # ------------------------ | ||
17 | # Enable extensions on systems that normally disable them, | ||
18 | # typically due to standards-conformance issues. | ||
19 | AC_DEFUN([AC_USE_SYSTEM_EXTENSIONS], | ||
20 | [ | ||
21 | AC_BEFORE([$0], [AC_COMPILE_IFELSE]) | ||
22 | AC_BEFORE([$0], [AC_RUN_IFELSE]) | ||
23 | |||
24 | AC_REQUIRE([AC_GNU_SOURCE]) | ||
25 | AC_REQUIRE([AC_AIX]) | ||
26 | AC_REQUIRE([AC_MINIX]) | ||
27 | |||
28 | AH_VERBATIM([__EXTENSIONS__], | ||
29 | [/* Enable extensions on Solaris. */ | ||
30 | #ifndef __EXTENSIONS__ | ||
31 | # undef __EXTENSIONS__ | ||
32 | #endif | ||
33 | #ifndef _POSIX_PTHREAD_SEMANTICS | ||
34 | # undef _POSIX_PTHREAD_SEMANTICS | ||
35 | #endif | ||
36 | #ifndef _TANDEM_SOURCE | ||
37 | # undef _TANDEM_SOURCE | ||
38 | #endif]) | ||
39 | AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__], | ||
40 | [ac_cv_safe_to_define___extensions__], | ||
41 | [AC_COMPILE_IFELSE( | ||
42 | [AC_LANG_PROGRAM([ | ||
43 | # define __EXTENSIONS__ 1 | ||
44 | AC_INCLUDES_DEFAULT])], | ||
45 | [ac_cv_safe_to_define___extensions__=yes], | ||
46 | [ac_cv_safe_to_define___extensions__=no])]) | ||
47 | test $ac_cv_safe_to_define___extensions__ = yes && | ||
48 | AC_DEFINE([__EXTENSIONS__]) | ||
49 | AC_DEFINE([_POSIX_PTHREAD_SEMANTICS]) | ||
50 | AC_DEFINE([_TANDEM_SOURCE]) | ||
51 | ]) | ||
52 | |||
53 | # gl_USE_SYSTEM_EXTENSIONS | ||
54 | # ------------------------ | ||
55 | # Enable extensions on systems that normally disable them, | ||
56 | # typically due to standards-conformance issues. | ||
57 | AC_DEFUN([gl_USE_SYSTEM_EXTENSIONS], | ||
58 | [AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])]) | ||
diff --git a/gl/m4/fcntl-safer.m4 b/gl/m4/fcntl-safer.m4 new file mode 100644 index 00000000..3475b0a7 --- /dev/null +++ b/gl/m4/fcntl-safer.m4 | |||
@@ -0,0 +1,11 @@ | |||
1 | #serial 5 | ||
2 | dnl Copyright (C) 2005-2007 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FCNTL_SAFER], | ||
8 | [ | ||
9 | AC_LIBOBJ([open-safer]) | ||
10 | AC_LIBOBJ([creat-safer]) | ||
11 | ]) | ||
diff --git a/gl/m4/fstypename.m4 b/gl/m4/fstypename.m4 new file mode 100644 index 00000000..aa676f3a --- /dev/null +++ b/gl/m4/fstypename.m4 | |||
@@ -0,0 +1,22 @@ | |||
1 | #serial 6 | ||
2 | |||
3 | dnl From Jim Meyering. | ||
4 | dnl | ||
5 | dnl See if struct statfs has the f_fstypename member. | ||
6 | dnl If so, define HAVE_STRUCT_STATFS_F_FSTYPENAME. | ||
7 | dnl | ||
8 | |||
9 | # Copyright (C) 1998, 1999, 2001, 2004, 2006 Free Software Foundation, Inc. | ||
10 | # This file is free software; the Free Software Foundation | ||
11 | # gives unlimited permission to copy and/or distribute it, | ||
12 | # with or without modifications, as long as this notice is preserved. | ||
13 | |||
14 | AC_DEFUN([gl_FSTYPENAME], | ||
15 | [ | ||
16 | AC_CHECK_MEMBERS([struct statfs.f_fstypename],,, | ||
17 | [ | ||
18 | #include <sys/types.h> | ||
19 | #include <sys/param.h> | ||
20 | #include <sys/mount.h> | ||
21 | ]) | ||
22 | ]) | ||
diff --git a/gl/m4/fsusage.m4 b/gl/m4/fsusage.m4 new file mode 100644 index 00000000..08bf06c9 --- /dev/null +++ b/gl/m4/fsusage.m4 | |||
@@ -0,0 +1,265 @@ | |||
1 | #serial 22 | ||
2 | # Obtaining file system usage information. | ||
3 | |||
4 | # Copyright (C) 1997, 1998, 2000, 2001, 2003, 2004, 2005, 2006 Free Software | ||
5 | # Foundation, Inc. | ||
6 | # | ||
7 | # This file is free software; the Free Software Foundation | ||
8 | # gives unlimited permission to copy and/or distribute it, | ||
9 | # with or without modifications, as long as this notice is preserved. | ||
10 | |||
11 | # Written by Jim Meyering. | ||
12 | |||
13 | AC_DEFUN([gl_FSUSAGE], | ||
14 | [ | ||
15 | AC_CHECK_HEADERS_ONCE(sys/param.h) | ||
16 | AC_CHECK_HEADERS_ONCE(sys/vfs.h sys/fs_types.h) | ||
17 | AC_CHECK_HEADERS(sys/mount.h, [], [], | ||
18 | [AC_INCLUDES_DEFAULT | ||
19 | [#if HAVE_SYS_PARAM_H | ||
20 | #include <sys/param.h> | ||
21 | #endif]]) | ||
22 | gl_FILE_SYSTEM_USAGE([gl_cv_fs_space=yes], [gl_cv_fs_space=no]) | ||
23 | if test $gl_cv_fs_space = yes; then | ||
24 | AC_LIBOBJ(fsusage) | ||
25 | gl_PREREQ_FSUSAGE_EXTRA | ||
26 | fi | ||
27 | ]) | ||
28 | |||
29 | # Try to determine how a program can obtain file system usage information. | ||
30 | # If successful, define the appropriate symbol (see fsusage.c) and | ||
31 | # execute ACTION-IF-FOUND. Otherwise, execute ACTION-IF-NOT-FOUND. | ||
32 | # | ||
33 | # gl_FILE_SYSTEM_USAGE([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) | ||
34 | |||
35 | AC_DEFUN([gl_FILE_SYSTEM_USAGE], | ||
36 | [ | ||
37 | |||
38 | AC_MSG_NOTICE([checking how to get file system space usage]) | ||
39 | ac_fsusage_space=no | ||
40 | |||
41 | # Perform only the link test since it seems there are no variants of the | ||
42 | # statvfs function. This check is more than just AC_CHECK_FUNCS(statvfs) | ||
43 | # because that got a false positive on SCO OSR5. Adding the declaration | ||
44 | # of a `struct statvfs' causes this test to fail (as it should) on such | ||
45 | # systems. That system is reported to work fine with STAT_STATFS4 which | ||
46 | # is what it gets when this test fails. | ||
47 | if test $ac_fsusage_space = no; then | ||
48 | # SVR4 | ||
49 | AC_CACHE_CHECK([for statvfs function (SVR4)], fu_cv_sys_stat_statvfs, | ||
50 | [AC_TRY_LINK([#include <sys/types.h> | ||
51 | #if defined __GLIBC__ && !defined __BEOS__ | ||
52 | Do not use statvfs on systems with GNU libc, because that function stats | ||
53 | all preceding entries in /proc/mounts, and that makes df hang if even | ||
54 | one of the corresponding file systems is hard-mounted, but not available. | ||
55 | statvfs in GNU libc on BeOS operates differently: it only makes a system | ||
56 | call. | ||
57 | #endif | ||
58 | #include <sys/statvfs.h>], | ||
59 | [struct statvfs fsd; statvfs (0, &fsd);], | ||
60 | fu_cv_sys_stat_statvfs=yes, | ||
61 | fu_cv_sys_stat_statvfs=no)]) | ||
62 | if test $fu_cv_sys_stat_statvfs = yes; then | ||
63 | ac_fsusage_space=yes | ||
64 | AC_DEFINE(STAT_STATVFS, 1, | ||
65 | [ Define if there is a function named statvfs. (SVR4)]) | ||
66 | fi | ||
67 | fi | ||
68 | |||
69 | if test $ac_fsusage_space = no; then | ||
70 | # DEC Alpha running OSF/1 | ||
71 | AC_MSG_CHECKING([for 3-argument statfs function (DEC OSF/1)]) | ||
72 | AC_CACHE_VAL(fu_cv_sys_stat_statfs3_osf1, | ||
73 | [AC_TRY_RUN([ | ||
74 | #include <sys/param.h> | ||
75 | #include <sys/types.h> | ||
76 | #include <sys/mount.h> | ||
77 | int | ||
78 | main () | ||
79 | { | ||
80 | struct statfs fsd; | ||
81 | fsd.f_fsize = 0; | ||
82 | return statfs (".", &fsd, sizeof (struct statfs)) != 0; | ||
83 | }], | ||
84 | fu_cv_sys_stat_statfs3_osf1=yes, | ||
85 | fu_cv_sys_stat_statfs3_osf1=no, | ||
86 | fu_cv_sys_stat_statfs3_osf1=no)]) | ||
87 | AC_MSG_RESULT($fu_cv_sys_stat_statfs3_osf1) | ||
88 | if test $fu_cv_sys_stat_statfs3_osf1 = yes; then | ||
89 | ac_fsusage_space=yes | ||
90 | AC_DEFINE(STAT_STATFS3_OSF1, 1, | ||
91 | [ Define if statfs takes 3 args. (DEC Alpha running OSF/1)]) | ||
92 | fi | ||
93 | fi | ||
94 | |||
95 | if test $ac_fsusage_space = no; then | ||
96 | # AIX | ||
97 | AC_MSG_CHECKING([for two-argument statfs with statfs.bsize dnl | ||
98 | member (AIX, 4.3BSD)]) | ||
99 | AC_CACHE_VAL(fu_cv_sys_stat_statfs2_bsize, | ||
100 | [AC_TRY_RUN([ | ||
101 | #ifdef HAVE_SYS_PARAM_H | ||
102 | #include <sys/param.h> | ||
103 | #endif | ||
104 | #ifdef HAVE_SYS_MOUNT_H | ||
105 | #include <sys/mount.h> | ||
106 | #endif | ||
107 | #ifdef HAVE_SYS_VFS_H | ||
108 | #include <sys/vfs.h> | ||
109 | #endif | ||
110 | int | ||
111 | main () | ||
112 | { | ||
113 | struct statfs fsd; | ||
114 | fsd.f_bsize = 0; | ||
115 | return statfs (".", &fsd) != 0; | ||
116 | }], | ||
117 | fu_cv_sys_stat_statfs2_bsize=yes, | ||
118 | fu_cv_sys_stat_statfs2_bsize=no, | ||
119 | fu_cv_sys_stat_statfs2_bsize=no)]) | ||
120 | AC_MSG_RESULT($fu_cv_sys_stat_statfs2_bsize) | ||
121 | if test $fu_cv_sys_stat_statfs2_bsize = yes; then | ||
122 | ac_fsusage_space=yes | ||
123 | AC_DEFINE(STAT_STATFS2_BSIZE, 1, | ||
124 | [ Define if statfs takes 2 args and struct statfs has a field named f_bsize. | ||
125 | (4.3BSD, SunOS 4, HP-UX, AIX PS/2)]) | ||
126 | fi | ||
127 | fi | ||
128 | |||
129 | if test $ac_fsusage_space = no; then | ||
130 | # SVR3 | ||
131 | AC_MSG_CHECKING([for four-argument statfs (AIX-3.2.5, SVR3)]) | ||
132 | AC_CACHE_VAL(fu_cv_sys_stat_statfs4, | ||
133 | [AC_TRY_RUN([#include <sys/types.h> | ||
134 | #include <sys/statfs.h> | ||
135 | int | ||
136 | main () | ||
137 | { | ||
138 | struct statfs fsd; | ||
139 | return statfs (".", &fsd, sizeof fsd, 0) != 0; | ||
140 | }], | ||
141 | fu_cv_sys_stat_statfs4=yes, | ||
142 | fu_cv_sys_stat_statfs4=no, | ||
143 | fu_cv_sys_stat_statfs4=no)]) | ||
144 | AC_MSG_RESULT($fu_cv_sys_stat_statfs4) | ||
145 | if test $fu_cv_sys_stat_statfs4 = yes; then | ||
146 | ac_fsusage_space=yes | ||
147 | AC_DEFINE(STAT_STATFS4, 1, | ||
148 | [ Define if statfs takes 4 args. (SVR3, Dynix, Irix, Dolphin)]) | ||
149 | fi | ||
150 | fi | ||
151 | |||
152 | if test $ac_fsusage_space = no; then | ||
153 | # 4.4BSD and NetBSD | ||
154 | AC_MSG_CHECKING([for two-argument statfs with statfs.fsize dnl | ||
155 | member (4.4BSD and NetBSD)]) | ||
156 | AC_CACHE_VAL(fu_cv_sys_stat_statfs2_fsize, | ||
157 | [AC_TRY_RUN([#include <sys/types.h> | ||
158 | #ifdef HAVE_SYS_PARAM_H | ||
159 | #include <sys/param.h> | ||
160 | #endif | ||
161 | #ifdef HAVE_SYS_MOUNT_H | ||
162 | #include <sys/mount.h> | ||
163 | #endif | ||
164 | int | ||
165 | main () | ||
166 | { | ||
167 | struct statfs fsd; | ||
168 | fsd.f_fsize = 0; | ||
169 | return statfs (".", &fsd) != 0; | ||
170 | }], | ||
171 | fu_cv_sys_stat_statfs2_fsize=yes, | ||
172 | fu_cv_sys_stat_statfs2_fsize=no, | ||
173 | fu_cv_sys_stat_statfs2_fsize=no)]) | ||
174 | AC_MSG_RESULT($fu_cv_sys_stat_statfs2_fsize) | ||
175 | if test $fu_cv_sys_stat_statfs2_fsize = yes; then | ||
176 | ac_fsusage_space=yes | ||
177 | AC_DEFINE(STAT_STATFS2_FSIZE, 1, | ||
178 | [ Define if statfs takes 2 args and struct statfs has a field named f_fsize. | ||
179 | (4.4BSD, NetBSD)]) | ||
180 | fi | ||
181 | fi | ||
182 | |||
183 | if test $ac_fsusage_space = no; then | ||
184 | # Ultrix | ||
185 | AC_MSG_CHECKING([for two-argument statfs with struct fs_data (Ultrix)]) | ||
186 | AC_CACHE_VAL(fu_cv_sys_stat_fs_data, | ||
187 | [AC_TRY_RUN([#include <sys/types.h> | ||
188 | #ifdef HAVE_SYS_PARAM_H | ||
189 | #include <sys/param.h> | ||
190 | #endif | ||
191 | #ifdef HAVE_SYS_MOUNT_H | ||
192 | #include <sys/mount.h> | ||
193 | #endif | ||
194 | #ifdef HAVE_SYS_FS_TYPES_H | ||
195 | #include <sys/fs_types.h> | ||
196 | #endif | ||
197 | int | ||
198 | main () | ||
199 | { | ||
200 | struct fs_data fsd; | ||
201 | /* Ultrix's statfs returns 1 for success, | ||
202 | 0 for not mounted, -1 for failure. */ | ||
203 | return statfs (".", &fsd) != 1; | ||
204 | }], | ||
205 | fu_cv_sys_stat_fs_data=yes, | ||
206 | fu_cv_sys_stat_fs_data=no, | ||
207 | fu_cv_sys_stat_fs_data=no)]) | ||
208 | AC_MSG_RESULT($fu_cv_sys_stat_fs_data) | ||
209 | if test $fu_cv_sys_stat_fs_data = yes; then | ||
210 | ac_fsusage_space=yes | ||
211 | AC_DEFINE(STAT_STATFS2_FS_DATA, 1, | ||
212 | [ Define if statfs takes 2 args and the second argument has | ||
213 | type struct fs_data. (Ultrix)]) | ||
214 | fi | ||
215 | fi | ||
216 | |||
217 | if test $ac_fsusage_space = no; then | ||
218 | # SVR2 | ||
219 | AC_TRY_CPP([#include <sys/filsys.h> | ||
220 | ], | ||
221 | AC_DEFINE(STAT_READ_FILSYS, 1, | ||
222 | [Define if there is no specific function for reading file systems usage | ||
223 | information and you have the <sys/filsys.h> header file. (SVR2)]) | ||
224 | ac_fsusage_space=yes) | ||
225 | fi | ||
226 | |||
227 | AS_IF([test $ac_fsusage_space = yes], [$1], [$2]) | ||
228 | |||
229 | ]) | ||
230 | |||
231 | |||
232 | # Check for SunOS statfs brokenness wrt partitions 2GB and larger. | ||
233 | # If <sys/vfs.h> exists and struct statfs has a member named f_spare, | ||
234 | # enable the work-around code in fsusage.c. | ||
235 | AC_DEFUN([gl_STATFS_TRUNCATES], | ||
236 | [ | ||
237 | AC_MSG_CHECKING([for statfs that truncates block counts]) | ||
238 | AC_CACHE_VAL(fu_cv_sys_truncating_statfs, | ||
239 | [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ | ||
240 | #if !defined(sun) && !defined(__sun) | ||
241 | choke -- this is a workaround for a Sun-specific problem | ||
242 | #endif | ||
243 | #include <sys/types.h> | ||
244 | #include <sys/vfs.h>]], | ||
245 | [[struct statfs t; long c = *(t.f_spare); | ||
246 | if (c) return 0;]])], | ||
247 | [fu_cv_sys_truncating_statfs=yes], | ||
248 | [fu_cv_sys_truncating_statfs=no])]) | ||
249 | if test $fu_cv_sys_truncating_statfs = yes; then | ||
250 | AC_DEFINE(STATFS_TRUNCATES_BLOCK_COUNTS, 1, | ||
251 | [Define if the block counts reported by statfs may be truncated to 2GB | ||
252 | and the correct values may be stored in the f_spare array. | ||
253 | (SunOS 4.1.2, 4.1.3, and 4.1.3_U1 are reported to have this problem. | ||
254 | SunOS 4.1.1 seems not to be affected.)]) | ||
255 | fi | ||
256 | AC_MSG_RESULT($fu_cv_sys_truncating_statfs) | ||
257 | ]) | ||
258 | |||
259 | |||
260 | # Prerequisites of lib/fsusage.c not done by gl_FILE_SYSTEM_USAGE. | ||
261 | AC_DEFUN([gl_PREREQ_FSUSAGE_EXTRA], | ||
262 | [ | ||
263 | AC_CHECK_HEADERS(dustat.h sys/fs/s5param.h sys/filsys.h sys/statfs.h) | ||
264 | gl_STATFS_TRUNCATES | ||
265 | ]) | ||
diff --git a/gl/m4/getaddrinfo.m4 b/gl/m4/getaddrinfo.m4 new file mode 100644 index 00000000..db285d94 --- /dev/null +++ b/gl/m4/getaddrinfo.m4 | |||
@@ -0,0 +1,88 @@ | |||
1 | # getaddrinfo.m4 serial 11 | ||
2 | dnl Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_GETADDRINFO], | ||
8 | [ | ||
9 | AC_MSG_NOTICE([checking how to do getaddrinfo, freeaddrinfo and getnameinfo]) | ||
10 | |||
11 | AC_SEARCH_LIBS(getaddrinfo, [nsl socket]) | ||
12 | AC_CHECK_FUNCS(getaddrinfo,, [ | ||
13 | AC_CACHE_CHECK(for getaddrinfo in ws2tcpip.h and -lws2_32, | ||
14 | gl_cv_w32_getaddrinfo, [ | ||
15 | gl_cv_w32_getaddrinfo=no | ||
16 | am_save_LIBS="$LIBS" | ||
17 | LIBS="$LIBS -lws2_32" | ||
18 | AC_TRY_LINK([ | ||
19 | #ifdef HAVE_WS2TCPIP_H | ||
20 | #include <ws2tcpip.h> | ||
21 | #endif | ||
22 | ], [getaddrinfo(0, 0, 0, 0);], gl_cv_w32_getaddrinfo=yes) | ||
23 | LIBS="$am_save_LIBS"]) | ||
24 | if test "$gl_cv_w32_getaddrinfo" = "yes"; then | ||
25 | LIBS="$LIBS -lws2_32" | ||
26 | else | ||
27 | AC_LIBOBJ(getaddrinfo) | ||
28 | fi | ||
29 | ]) | ||
30 | |||
31 | AC_REPLACE_FUNCS(gai_strerror) | ||
32 | gl_PREREQ_GETADDRINFO | ||
33 | ]) | ||
34 | |||
35 | # Prerequisites of lib/getaddrinfo.h and lib/getaddrinfo.c. | ||
36 | AC_DEFUN([gl_PREREQ_GETADDRINFO], [ | ||
37 | AC_SEARCH_LIBS(gethostbyname, [inet nsl]) | ||
38 | AC_SEARCH_LIBS(getservbyname, [inet nsl socket xnet]) | ||
39 | AC_CHECK_FUNCS(gethostbyname,, [ | ||
40 | AC_CACHE_CHECK(for gethostbyname in winsock2.h and -lws2_32, | ||
41 | gl_cv_w32_gethostbyname, [ | ||
42 | gl_cv_w32_gethostbyname=no | ||
43 | am_save_LIBS="$LIBS" | ||
44 | LIBS="$LIBS -lws2_32" | ||
45 | AC_TRY_LINK([ | ||
46 | #ifdef HAVE_WINSOCK2_H | ||
47 | #include <winsock2.h> | ||
48 | #endif | ||
49 | ], [gethostbyname(0);], gl_cv_w32_gethostbyname=yes) | ||
50 | LIBS="$am_save_LIBS"]) | ||
51 | if test "$gl_cv_w32_gethostbyname" = "yes"; then | ||
52 | LIBS="$LIBS -lws2_32" | ||
53 | fi | ||
54 | ]) | ||
55 | AC_REQUIRE([AC_C_RESTRICT]) | ||
56 | AC_REQUIRE([gl_SOCKET_FAMILIES]) | ||
57 | AC_REQUIRE([gl_HEADER_SYS_SOCKET]) | ||
58 | AC_REQUIRE([AC_C_INLINE]) | ||
59 | AC_REQUIRE([AC_GNU_SOURCE]) | ||
60 | AC_CHECK_HEADERS_ONCE(netinet/in.h netdb.h) | ||
61 | AC_CHECK_DECLS([getaddrinfo, freeaddrinfo, gai_strerror, getnameinfo],,,[ | ||
62 | /* sys/types.h is not needed according to POSIX, but the | ||
63 | sys/socket.h in i386-unknown-freebsd4.10 and | ||
64 | powerpc-apple-darwin5.5 required it. */ | ||
65 | #include <sys/types.h> | ||
66 | #ifdef HAVE_SYS_SOCKET_H | ||
67 | #include <sys/socket.h> | ||
68 | #endif | ||
69 | #ifdef HAVE_NETDB_H | ||
70 | #include <netdb.h> | ||
71 | #endif | ||
72 | #ifdef HAVE_WS2TCPIP_H | ||
73 | #include <ws2tcpip.h> | ||
74 | #endif | ||
75 | ]) | ||
76 | AC_CHECK_TYPES([struct addrinfo],,,[ | ||
77 | #include <sys/types.h> | ||
78 | #ifdef HAVE_SYS_SOCKET_H | ||
79 | #include <sys/socket.h> | ||
80 | #endif | ||
81 | #ifdef HAVE_NETDB_H | ||
82 | #include <netdb.h> | ||
83 | #endif | ||
84 | #ifdef HAVE_WS2TCPIP_H | ||
85 | #include <ws2tcpip.h> | ||
86 | #endif | ||
87 | ]) | ||
88 | ]) | ||
diff --git a/gl/m4/gethostname.m4 b/gl/m4/gethostname.m4 new file mode 100644 index 00000000..1e9749d3 --- /dev/null +++ b/gl/m4/gethostname.m4 | |||
@@ -0,0 +1,18 @@ | |||
1 | # gethostname.m4 serial 2 | ||
2 | dnl Copyright (C) 2002 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FUNC_GETHOSTNAME], | ||
8 | [ | ||
9 | AC_REPLACE_FUNCS(gethostname) | ||
10 | if test $ac_cv_func_gethostname = no; then | ||
11 | gl_PREREQ_GETHOSTNAME | ||
12 | fi | ||
13 | ]) | ||
14 | |||
15 | # Prerequisites of lib/gethostname.c. | ||
16 | AC_DEFUN([gl_PREREQ_GETHOSTNAME], [ | ||
17 | AC_CHECK_FUNCS(uname) | ||
18 | ]) | ||
diff --git a/gl/m4/getloadavg.m4 b/gl/m4/getloadavg.m4 new file mode 100644 index 00000000..82437291 --- /dev/null +++ b/gl/m4/getloadavg.m4 | |||
@@ -0,0 +1,155 @@ | |||
1 | # Check for getloadavg. | ||
2 | |||
3 | # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1999, 2000, 2002, 2003, | ||
4 | # 2006 Free Software Foundation, Inc. | ||
5 | |||
6 | # This file is free software; the Free Software Foundation | ||
7 | # gives unlimited permission to copy and/or distribute it, | ||
8 | # with or without modifications, as long as this notice is preserved. | ||
9 | |||
10 | # Autoconf defines AC_FUNC_GETLOADAVG, but that is obsolescent. | ||
11 | # New applications should use gl_GETLOADAVG instead. | ||
12 | |||
13 | # gl_GETLOADAVG(LIBOBJDIR) | ||
14 | # ------------------------ | ||
15 | AC_DEFUN([gl_GETLOADAVG], | ||
16 | [gl_have_func=no # yes means we've found a way to get the load average. | ||
17 | |||
18 | # Make sure getloadavg.c is where it belongs, at configure-time. | ||
19 | test -f "$srcdir/$1/getloadavg.c" || | ||
20 | AC_MSG_ERROR([$srcdir/$1/getloadavg.c is missing]) | ||
21 | |||
22 | gl_save_LIBS=$LIBS | ||
23 | |||
24 | # Check for getloadavg, but be sure not to touch the cache variable. | ||
25 | (AC_CHECK_FUNC(getloadavg, exit 0, exit 1)) && gl_have_func=yes | ||
26 | |||
27 | # On HPUX9, an unprivileged user can get load averages through this function. | ||
28 | AC_CHECK_FUNCS(pstat_getdynamic) | ||
29 | |||
30 | # Solaris has libkstat which does not require root. | ||
31 | AC_CHECK_LIB(kstat, kstat_open) | ||
32 | test $ac_cv_lib_kstat_kstat_open = yes && gl_have_func=yes | ||
33 | |||
34 | # Some systems with -lutil have (and need) -lkvm as well, some do not. | ||
35 | # On Solaris, -lkvm requires nlist from -lelf, so check that first | ||
36 | # to get the right answer into the cache. | ||
37 | # For kstat on solaris, we need libelf to force the definition of SVR4 below. | ||
38 | if test $gl_have_func = no; then | ||
39 | AC_CHECK_LIB(elf, elf_begin, LIBS="-lelf $LIBS") | ||
40 | fi | ||
41 | if test $gl_have_func = no; then | ||
42 | AC_CHECK_LIB(kvm, kvm_open, LIBS="-lkvm $LIBS") | ||
43 | # Check for the 4.4BSD definition of getloadavg. | ||
44 | AC_CHECK_LIB(util, getloadavg, | ||
45 | [LIBS="-lutil $LIBS" gl_have_func=yes gl_cv_func_getloadavg_setgid=yes]) | ||
46 | fi | ||
47 | |||
48 | if test $gl_have_func = no; then | ||
49 | # There is a commonly available library for RS/6000 AIX. | ||
50 | # Since it is not a standard part of AIX, it might be installed locally. | ||
51 | gl_getloadavg_LIBS=$LIBS | ||
52 | LIBS="-L/usr/local/lib $LIBS" | ||
53 | AC_CHECK_LIB(getloadavg, getloadavg, | ||
54 | [LIBS="-lgetloadavg $LIBS"], [LIBS=$gl_getloadavg_LIBS]) | ||
55 | fi | ||
56 | |||
57 | # Make sure it is really in the library, if we think we found it, | ||
58 | # otherwise set up the replacement function. | ||
59 | AC_CHECK_FUNCS(getloadavg, [], | ||
60 | [gl_PREREQ_GETLOADAVG]) | ||
61 | |||
62 | # Some definitions of getloadavg require that the program be installed setgid. | ||
63 | AC_CACHE_CHECK(whether getloadavg requires setgid, | ||
64 | gl_cv_func_getloadavg_setgid, | ||
65 | [AC_EGREP_CPP([Yowza Am I SETGID yet], | ||
66 | [#define CONFIGURING_GETLOADAVG | ||
67 | #include "$srcdir/$1/getloadavg.c" | ||
68 | #ifdef LDAV_PRIVILEGED | ||
69 | Yowza Am I SETGID yet | ||
70 | #endif | ||
71 | ], | ||
72 | gl_cv_func_getloadavg_setgid=yes, | ||
73 | gl_cv_func_getloadavg_setgid=no)]) | ||
74 | if test $gl_cv_func_getloadavg_setgid = yes; then | ||
75 | NEED_SETGID=true | ||
76 | AC_DEFINE(GETLOADAVG_PRIVILEGED, 1, | ||
77 | [Define to 1 if the `getloadavg' function needs to be run setuid | ||
78 | or setgid.]) | ||
79 | else | ||
80 | NEED_SETGID=false | ||
81 | fi | ||
82 | AC_SUBST(NEED_SETGID)dnl | ||
83 | |||
84 | if test $gl_cv_func_getloadavg_setgid = yes; then | ||
85 | AC_CACHE_CHECK(group of /dev/kmem, gl_cv_group_kmem, | ||
86 | [ # On Solaris, /dev/kmem is a symlink. Get info on the real file. | ||
87 | ac_ls_output=`ls -lgL /dev/kmem 2>/dev/null` | ||
88 | # If we got an error (system does not support symlinks), try without -L. | ||
89 | test -z "$ac_ls_output" && ac_ls_output=`ls -lg /dev/kmem` | ||
90 | gl_cv_group_kmem=`echo $ac_ls_output \ | ||
91 | | sed -ne ['s/[ ][ ]*/ /g | ||
92 | s/^.[sSrwx-]* *[0-9]* *\([^0-9]*\) *.*/\1/ | ||
93 | / /s/.* //;p']` | ||
94 | ]) | ||
95 | AC_SUBST(KMEM_GROUP, $gl_cv_group_kmem)dnl | ||
96 | fi | ||
97 | if test "x$gl_save_LIBS" = x; then | ||
98 | GETLOADAVG_LIBS=$LIBS | ||
99 | else | ||
100 | GETLOADAVG_LIBS=`echo "$LIBS" | sed "s!$gl_save_LIBS!!"` | ||
101 | fi | ||
102 | LIBS=$gl_save_LIBS | ||
103 | |||
104 | AC_SUBST(GETLOADAVG_LIBS)dnl | ||
105 | ])# gl_GETLOADAVG | ||
106 | |||
107 | |||
108 | # gl_PREREQ_GETLOADAVG | ||
109 | # -------------------- | ||
110 | # Set up the AC_LIBOBJ replacement of `getloadavg'. | ||
111 | AC_DEFUN([gl_PREREQ_GETLOADAVG], | ||
112 | [AC_LIBOBJ(getloadavg) | ||
113 | AC_DEFINE(C_GETLOADAVG, 1, [Define to 1 if using `getloadavg.c'.]) | ||
114 | # Figure out what our getloadavg.c needs. | ||
115 | gl_have_func=no | ||
116 | AC_CHECK_HEADER(sys/dg_sys_info.h, | ||
117 | [gl_have_func=yes | ||
118 | AC_DEFINE(DGUX, 1, [Define to 1 for DGUX with <sys/dg_sys_info.h>.]) | ||
119 | AC_CHECK_LIB(dgc, dg_sys_info)]) | ||
120 | |||
121 | # We cannot check for <dwarf.h>, because Solaris 2 does not use dwarf (it | ||
122 | # uses stabs), but it is still SVR4. We cannot check for <elf.h> because | ||
123 | # Irix 4.0.5F has the header but not the library. | ||
124 | if test $gl_have_func = no && test "$ac_cv_lib_elf_elf_begin" = yes; then | ||
125 | gl_have_func=yes | ||
126 | AC_DEFINE(SVR4, 1, [Define to 1 on System V Release 4.]) | ||
127 | fi | ||
128 | |||
129 | if test $gl_have_func = no; then | ||
130 | AC_CHECK_HEADER(inq_stats/cpustats.h, | ||
131 | [gl_have_func=yes | ||
132 | AC_DEFINE(UMAX, 1, [Define to 1 for Encore UMAX.]) | ||
133 | AC_DEFINE(UMAX4_3, 1, | ||
134 | [Define to 1 for Encore UMAX 4.3 that has <inq_status/cpustats.h> | ||
135 | instead of <sys/cpustats.h>.])]) | ||
136 | fi | ||
137 | |||
138 | if test $gl_have_func = no; then | ||
139 | AC_CHECK_HEADER(sys/cpustats.h, | ||
140 | [gl_have_func=yes; AC_DEFINE(UMAX)]) | ||
141 | fi | ||
142 | |||
143 | if test $gl_have_func = no; then | ||
144 | AC_CHECK_HEADERS(mach/mach.h) | ||
145 | fi | ||
146 | |||
147 | AC_CHECK_HEADERS(nlist.h, | ||
148 | [AC_CHECK_MEMBERS([struct nlist.n_un.n_name], | ||
149 | [AC_DEFINE(NLIST_NAME_UNION, 1, | ||
150 | [Define to 1 if your `struct nlist' has an | ||
151 | `n_un' member. Obsolete, depend on | ||
152 | `HAVE_STRUCT_NLIST_N_UN_N_NAME])], [], | ||
153 | [@%:@include <nlist.h>]) | ||
154 | ])dnl | ||
155 | ])# gl_PREREQ_GETLOADAVG | ||
diff --git a/gl/m4/getopt.m4 b/gl/m4/getopt.m4 new file mode 100644 index 00000000..c0a73b2c --- /dev/null +++ b/gl/m4/getopt.m4 | |||
@@ -0,0 +1,83 @@ | |||
1 | # getopt.m4 serial 13 | ||
2 | dnl Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | # The getopt module assume you want GNU getopt, with getopt_long etc, | ||
8 | # rather than vanilla POSIX getopt. This means your code should | ||
9 | # always include <getopt.h> for the getopt prototypes. | ||
10 | |||
11 | AC_DEFUN([gl_GETOPT_SUBSTITUTE], | ||
12 | [ | ||
13 | AC_LIBOBJ([getopt]) | ||
14 | AC_LIBOBJ([getopt1]) | ||
15 | gl_GETOPT_SUBSTITUTE_HEADER | ||
16 | gl_PREREQ_GETOPT | ||
17 | ]) | ||
18 | |||
19 | AC_DEFUN([gl_GETOPT_SUBSTITUTE_HEADER], | ||
20 | [ | ||
21 | GETOPT_H=getopt.h | ||
22 | AC_DEFINE([__GETOPT_PREFIX], [[rpl_]], | ||
23 | [Define to rpl_ if the getopt replacement functions and variables | ||
24 | should be used.]) | ||
25 | AC_SUBST([GETOPT_H]) | ||
26 | ]) | ||
27 | |||
28 | AC_DEFUN([gl_GETOPT_CHECK_HEADERS], | ||
29 | [ | ||
30 | if test -z "$GETOPT_H"; then | ||
31 | AC_CHECK_HEADERS([getopt.h], [], [GETOPT_H=getopt.h]) | ||
32 | fi | ||
33 | |||
34 | if test -z "$GETOPT_H"; then | ||
35 | AC_CHECK_FUNCS([getopt_long_only], [], [GETOPT_H=getopt.h]) | ||
36 | fi | ||
37 | |||
38 | dnl BSD getopt_long uses an incompatible method to reset option processing, | ||
39 | dnl and (as of 2004-10-15) mishandles optional option-arguments. | ||
40 | if test -z "$GETOPT_H"; then | ||
41 | AC_CHECK_DECL([optreset], [GETOPT_H=getopt.h], [], [#include <getopt.h>]) | ||
42 | fi | ||
43 | |||
44 | dnl Solaris 10 getopt doesn't handle `+' as a leading character in an | ||
45 | dnl option string (as of 2005-05-05). | ||
46 | if test -z "$GETOPT_H"; then | ||
47 | AC_CACHE_CHECK([for working GNU getopt function], [gl_cv_func_gnu_getopt], | ||
48 | [AC_RUN_IFELSE( | ||
49 | [AC_LANG_PROGRAM([#include <getopt.h>], | ||
50 | [[ | ||
51 | char *myargv[3]; | ||
52 | myargv[0] = "conftest"; | ||
53 | myargv[1] = "-+"; | ||
54 | myargv[2] = 0; | ||
55 | return getopt (2, myargv, "+a") != '?'; | ||
56 | ]])], | ||
57 | [gl_cv_func_gnu_getopt=yes], | ||
58 | [gl_cv_func_gnu_getopt=no], | ||
59 | [dnl cross compiling - pessimistically guess based on decls | ||
60 | dnl Solaris 10 getopt doesn't handle `+' as a leading character in an | ||
61 | dnl option string (as of 2005-05-05). | ||
62 | AC_CHECK_DECL([getopt_clip], | ||
63 | [gl_cv_func_gnu_getopt=no], [gl_cv_func_gnu_getopt=yes], | ||
64 | [#include <getopt.h>])])]) | ||
65 | if test "$gl_cv_func_gnu_getopt" = "no"; then | ||
66 | GETOPT_H=getopt.h | ||
67 | fi | ||
68 | fi | ||
69 | ]) | ||
70 | |||
71 | AC_DEFUN([gl_GETOPT_IFELSE], | ||
72 | [ | ||
73 | AC_REQUIRE([gl_GETOPT_CHECK_HEADERS]) | ||
74 | AS_IF([test -n "$GETOPT_H"], [$1], [$2]) | ||
75 | ]) | ||
76 | |||
77 | AC_DEFUN([gl_GETOPT], [gl_GETOPT_IFELSE([gl_GETOPT_SUBSTITUTE])]) | ||
78 | |||
79 | # Prerequisites of lib/getopt*. | ||
80 | AC_DEFUN([gl_PREREQ_GETOPT], | ||
81 | [ | ||
82 | AC_CHECK_DECLS_ONCE([getenv]) | ||
83 | ]) | ||
diff --git a/gl/m4/gettext.m4 b/gl/m4/gettext.m4 new file mode 100644 index 00000000..91c345e9 --- /dev/null +++ b/gl/m4/gettext.m4 | |||
@@ -0,0 +1,419 @@ | |||
1 | # gettext.m4 serial 59 (gettext-0.16.1) | ||
2 | dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | dnl | ||
7 | dnl This file can can be used in projects which are not available under | ||
8 | dnl the GNU General Public License or the GNU Library General Public | ||
9 | dnl License but which still want to provide support for the GNU gettext | ||
10 | dnl functionality. | ||
11 | dnl Please note that the actual code of the GNU gettext library is covered | ||
12 | dnl by the GNU Library General Public License, and the rest of the GNU | ||
13 | dnl gettext package package is covered by the GNU General Public License. | ||
14 | dnl They are *not* in the public domain. | ||
15 | |||
16 | dnl Authors: | ||
17 | dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. | ||
18 | dnl Bruno Haible <haible@clisp.cons.org>, 2000-2006. | ||
19 | |||
20 | dnl Macro to add for using GNU gettext. | ||
21 | |||
22 | dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). | ||
23 | dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The | ||
24 | dnl default (if it is not specified or empty) is 'no-libtool'. | ||
25 | dnl INTLSYMBOL should be 'external' for packages with no intl directory, | ||
26 | dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. | ||
27 | dnl If INTLSYMBOL is 'use-libtool', then a libtool library | ||
28 | dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, | ||
29 | dnl depending on --{enable,disable}-{shared,static} and on the presence of | ||
30 | dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library | ||
31 | dnl $(top_builddir)/intl/libintl.a will be created. | ||
32 | dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext | ||
33 | dnl implementations (in libc or libintl) without the ngettext() function | ||
34 | dnl will be ignored. If NEEDSYMBOL is specified and is | ||
35 | dnl 'need-formatstring-macros', then GNU gettext implementations that don't | ||
36 | dnl support the ISO C 99 <inttypes.h> formatstring macros will be ignored. | ||
37 | dnl INTLDIR is used to find the intl libraries. If empty, | ||
38 | dnl the value `$(top_builddir)/intl/' is used. | ||
39 | dnl | ||
40 | dnl The result of the configuration is one of three cases: | ||
41 | dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled | ||
42 | dnl and used. | ||
43 | dnl Catalog format: GNU --> install in $(datadir) | ||
44 | dnl Catalog extension: .mo after installation, .gmo in source tree | ||
45 | dnl 2) GNU gettext has been found in the system's C library. | ||
46 | dnl Catalog format: GNU --> install in $(datadir) | ||
47 | dnl Catalog extension: .mo after installation, .gmo in source tree | ||
48 | dnl 3) No internationalization, always use English msgid. | ||
49 | dnl Catalog format: none | ||
50 | dnl Catalog extension: none | ||
51 | dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. | ||
52 | dnl The use of .gmo is historical (it was needed to avoid overwriting the | ||
53 | dnl GNU format catalogs when building on a platform with an X/Open gettext), | ||
54 | dnl but we keep it in order not to force irrelevant filename changes on the | ||
55 | dnl maintainers. | ||
56 | dnl | ||
57 | AC_DEFUN([AM_GNU_GETTEXT], | ||
58 | [ | ||
59 | dnl Argument checking. | ||
60 | ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , | ||
61 | [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT | ||
62 | ])])])])]) | ||
63 | ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , | ||
64 | [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT | ||
65 | ])])])]) | ||
66 | define([gt_included_intl], | ||
67 | ifelse([$1], [external], | ||
68 | ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]), | ||
69 | [yes])) | ||
70 | define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) | ||
71 | gt_NEEDS_INIT | ||
72 | AM_GNU_GETTEXT_NEED([$2]) | ||
73 | |||
74 | AC_REQUIRE([AM_PO_SUBDIRS])dnl | ||
75 | ifelse(gt_included_intl, yes, [ | ||
76 | AC_REQUIRE([AM_INTL_SUBDIR])dnl | ||
77 | ]) | ||
78 | |||
79 | dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. | ||
80 | AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) | ||
81 | AC_REQUIRE([AC_LIB_RPATH]) | ||
82 | |||
83 | dnl Sometimes libintl requires libiconv, so first search for libiconv. | ||
84 | dnl Ideally we would do this search only after the | ||
85 | dnl if test "$USE_NLS" = "yes"; then | ||
86 | dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then | ||
87 | dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT | ||
88 | dnl the configure script would need to contain the same shell code | ||
89 | dnl again, outside any 'if'. There are two solutions: | ||
90 | dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. | ||
91 | dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. | ||
92 | dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not | ||
93 | dnl documented, we avoid it. | ||
94 | ifelse(gt_included_intl, yes, , [ | ||
95 | AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) | ||
96 | ]) | ||
97 | |||
98 | dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation. | ||
99 | gt_INTL_MACOSX | ||
100 | |||
101 | dnl Set USE_NLS. | ||
102 | AC_REQUIRE([AM_NLS]) | ||
103 | |||
104 | ifelse(gt_included_intl, yes, [ | ||
105 | BUILD_INCLUDED_LIBINTL=no | ||
106 | USE_INCLUDED_LIBINTL=no | ||
107 | ]) | ||
108 | LIBINTL= | ||
109 | LTLIBINTL= | ||
110 | POSUB= | ||
111 | |||
112 | dnl Add a version number to the cache macros. | ||
113 | case " $gt_needs " in | ||
114 | *" need-formatstring-macros "*) gt_api_version=3 ;; | ||
115 | *" need-ngettext "*) gt_api_version=2 ;; | ||
116 | *) gt_api_version=1 ;; | ||
117 | esac | ||
118 | gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" | ||
119 | gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" | ||
120 | |||
121 | dnl If we use NLS figure out what method | ||
122 | if test "$USE_NLS" = "yes"; then | ||
123 | gt_use_preinstalled_gnugettext=no | ||
124 | ifelse(gt_included_intl, yes, [ | ||
125 | AC_MSG_CHECKING([whether included gettext is requested]) | ||
126 | AC_ARG_WITH(included-gettext, | ||
127 | [ --with-included-gettext use the GNU gettext library included here], | ||
128 | nls_cv_force_use_gnu_gettext=$withval, | ||
129 | nls_cv_force_use_gnu_gettext=no) | ||
130 | AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) | ||
131 | |||
132 | nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" | ||
133 | if test "$nls_cv_force_use_gnu_gettext" != "yes"; then | ||
134 | ]) | ||
135 | dnl User does not insist on using GNU NLS library. Figure out what | ||
136 | dnl to use. If GNU gettext is available we use this. Else we have | ||
137 | dnl to fall back to GNU NLS library. | ||
138 | |||
139 | if test $gt_api_version -ge 3; then | ||
140 | gt_revision_test_code=' | ||
141 | #ifndef __GNU_GETTEXT_SUPPORTED_REVISION | ||
142 | #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) | ||
143 | #endif | ||
144 | changequote(,)dnl | ||
145 | typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; | ||
146 | changequote([,])dnl | ||
147 | ' | ||
148 | else | ||
149 | gt_revision_test_code= | ||
150 | fi | ||
151 | if test $gt_api_version -ge 2; then | ||
152 | gt_expression_test_code=' + * ngettext ("", "", 0)' | ||
153 | else | ||
154 | gt_expression_test_code= | ||
155 | fi | ||
156 | |||
157 | AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc], | ||
158 | [AC_TRY_LINK([#include <libintl.h> | ||
159 | $gt_revision_test_code | ||
160 | extern int _nl_msg_cat_cntr; | ||
161 | extern int *_nl_domain_bindings;], | ||
162 | [bindtextdomain ("", ""); | ||
163 | return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings], | ||
164 | [eval "$gt_func_gnugettext_libc=yes"], | ||
165 | [eval "$gt_func_gnugettext_libc=no"])]) | ||
166 | |||
167 | if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then | ||
168 | dnl Sometimes libintl requires libiconv, so first search for libiconv. | ||
169 | ifelse(gt_included_intl, yes, , [ | ||
170 | AM_ICONV_LINK | ||
171 | ]) | ||
172 | dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL | ||
173 | dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) | ||
174 | dnl because that would add "-liconv" to LIBINTL and LTLIBINTL | ||
175 | dnl even if libiconv doesn't exist. | ||
176 | AC_LIB_LINKFLAGS_BODY([intl]) | ||
177 | AC_CACHE_CHECK([for GNU gettext in libintl], | ||
178 | [$gt_func_gnugettext_libintl], | ||
179 | [gt_save_CPPFLAGS="$CPPFLAGS" | ||
180 | CPPFLAGS="$CPPFLAGS $INCINTL" | ||
181 | gt_save_LIBS="$LIBS" | ||
182 | LIBS="$LIBS $LIBINTL" | ||
183 | dnl Now see whether libintl exists and does not depend on libiconv. | ||
184 | AC_TRY_LINK([#include <libintl.h> | ||
185 | $gt_revision_test_code | ||
186 | extern int _nl_msg_cat_cntr; | ||
187 | extern | ||
188 | #ifdef __cplusplus | ||
189 | "C" | ||
190 | #endif | ||
191 | const char *_nl_expand_alias (const char *);], | ||
192 | [bindtextdomain ("", ""); | ||
193 | return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], | ||
194 | [eval "$gt_func_gnugettext_libintl=yes"], | ||
195 | [eval "$gt_func_gnugettext_libintl=no"]) | ||
196 | dnl Now see whether libintl exists and depends on libiconv. | ||
197 | if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then | ||
198 | LIBS="$LIBS $LIBICONV" | ||
199 | AC_TRY_LINK([#include <libintl.h> | ||
200 | $gt_revision_test_code | ||
201 | extern int _nl_msg_cat_cntr; | ||
202 | extern | ||
203 | #ifdef __cplusplus | ||
204 | "C" | ||
205 | #endif | ||
206 | const char *_nl_expand_alias (const char *);], | ||
207 | [bindtextdomain ("", ""); | ||
208 | return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], | ||
209 | [LIBINTL="$LIBINTL $LIBICONV" | ||
210 | LTLIBINTL="$LTLIBINTL $LTLIBICONV" | ||
211 | eval "$gt_func_gnugettext_libintl=yes" | ||
212 | ]) | ||
213 | fi | ||
214 | CPPFLAGS="$gt_save_CPPFLAGS" | ||
215 | LIBS="$gt_save_LIBS"]) | ||
216 | fi | ||
217 | |||
218 | dnl If an already present or preinstalled GNU gettext() is found, | ||
219 | dnl use it. But if this macro is used in GNU gettext, and GNU | ||
220 | dnl gettext is already preinstalled in libintl, we update this | ||
221 | dnl libintl. (Cf. the install rule in intl/Makefile.in.) | ||
222 | if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ | ||
223 | || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ | ||
224 | && test "$PACKAGE" != gettext-runtime \ | ||
225 | && test "$PACKAGE" != gettext-tools; }; then | ||
226 | gt_use_preinstalled_gnugettext=yes | ||
227 | else | ||
228 | dnl Reset the values set by searching for libintl. | ||
229 | LIBINTL= | ||
230 | LTLIBINTL= | ||
231 | INCINTL= | ||
232 | fi | ||
233 | |||
234 | ifelse(gt_included_intl, yes, [ | ||
235 | if test "$gt_use_preinstalled_gnugettext" != "yes"; then | ||
236 | dnl GNU gettext is not found in the C library. | ||
237 | dnl Fall back on included GNU gettext library. | ||
238 | nls_cv_use_gnu_gettext=yes | ||
239 | fi | ||
240 | fi | ||
241 | |||
242 | if test "$nls_cv_use_gnu_gettext" = "yes"; then | ||
243 | dnl Mark actions used to generate GNU NLS library. | ||
244 | BUILD_INCLUDED_LIBINTL=yes | ||
245 | USE_INCLUDED_LIBINTL=yes | ||
246 | LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD" | ||
247 | LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD" | ||
248 | LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` | ||
249 | fi | ||
250 | |||
251 | CATOBJEXT= | ||
252 | if test "$gt_use_preinstalled_gnugettext" = "yes" \ | ||
253 | || test "$nls_cv_use_gnu_gettext" = "yes"; then | ||
254 | dnl Mark actions to use GNU gettext tools. | ||
255 | CATOBJEXT=.gmo | ||
256 | fi | ||
257 | ]) | ||
258 | |||
259 | if test -n "$INTL_MACOSX_LIBS"; then | ||
260 | if test "$gt_use_preinstalled_gnugettext" = "yes" \ | ||
261 | || test "$nls_cv_use_gnu_gettext" = "yes"; then | ||
262 | dnl Some extra flags are needed during linking. | ||
263 | LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" | ||
264 | LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" | ||
265 | fi | ||
266 | fi | ||
267 | |||
268 | if test "$gt_use_preinstalled_gnugettext" = "yes" \ | ||
269 | || test "$nls_cv_use_gnu_gettext" = "yes"; then | ||
270 | AC_DEFINE(ENABLE_NLS, 1, | ||
271 | [Define to 1 if translation of program messages to the user's native language | ||
272 | is requested.]) | ||
273 | else | ||
274 | USE_NLS=no | ||
275 | fi | ||
276 | fi | ||
277 | |||
278 | AC_MSG_CHECKING([whether to use NLS]) | ||
279 | AC_MSG_RESULT([$USE_NLS]) | ||
280 | if test "$USE_NLS" = "yes"; then | ||
281 | AC_MSG_CHECKING([where the gettext function comes from]) | ||
282 | if test "$gt_use_preinstalled_gnugettext" = "yes"; then | ||
283 | if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then | ||
284 | gt_source="external libintl" | ||
285 | else | ||
286 | gt_source="libc" | ||
287 | fi | ||
288 | else | ||
289 | gt_source="included intl directory" | ||
290 | fi | ||
291 | AC_MSG_RESULT([$gt_source]) | ||
292 | fi | ||
293 | |||
294 | if test "$USE_NLS" = "yes"; then | ||
295 | |||
296 | if test "$gt_use_preinstalled_gnugettext" = "yes"; then | ||
297 | if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then | ||
298 | AC_MSG_CHECKING([how to link with libintl]) | ||
299 | AC_MSG_RESULT([$LIBINTL]) | ||
300 | AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) | ||
301 | fi | ||
302 | |||
303 | dnl For backward compatibility. Some packages may be using this. | ||
304 | AC_DEFINE(HAVE_GETTEXT, 1, | ||
305 | [Define if the GNU gettext() function is already present or preinstalled.]) | ||
306 | AC_DEFINE(HAVE_DCGETTEXT, 1, | ||
307 | [Define if the GNU dcgettext() function is already present or preinstalled.]) | ||
308 | fi | ||
309 | |||
310 | dnl We need to process the po/ directory. | ||
311 | POSUB=po | ||
312 | fi | ||
313 | |||
314 | ifelse(gt_included_intl, yes, [ | ||
315 | dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL | ||
316 | dnl to 'yes' because some of the testsuite requires it. | ||
317 | if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then | ||
318 | BUILD_INCLUDED_LIBINTL=yes | ||
319 | fi | ||
320 | |||
321 | dnl Make all variables we use known to autoconf. | ||
322 | AC_SUBST(BUILD_INCLUDED_LIBINTL) | ||
323 | AC_SUBST(USE_INCLUDED_LIBINTL) | ||
324 | AC_SUBST(CATOBJEXT) | ||
325 | |||
326 | dnl For backward compatibility. Some configure.ins may be using this. | ||
327 | nls_cv_header_intl= | ||
328 | nls_cv_header_libgt= | ||
329 | |||
330 | dnl For backward compatibility. Some Makefiles may be using this. | ||
331 | DATADIRNAME=share | ||
332 | AC_SUBST(DATADIRNAME) | ||
333 | |||
334 | dnl For backward compatibility. Some Makefiles may be using this. | ||
335 | INSTOBJEXT=.mo | ||
336 | AC_SUBST(INSTOBJEXT) | ||
337 | |||
338 | dnl For backward compatibility. Some Makefiles may be using this. | ||
339 | GENCAT=gencat | ||
340 | AC_SUBST(GENCAT) | ||
341 | |||
342 | dnl For backward compatibility. Some Makefiles may be using this. | ||
343 | INTLOBJS= | ||
344 | if test "$USE_INCLUDED_LIBINTL" = yes; then | ||
345 | INTLOBJS="\$(GETTOBJS)" | ||
346 | fi | ||
347 | AC_SUBST(INTLOBJS) | ||
348 | |||
349 | dnl Enable libtool support if the surrounding package wishes it. | ||
350 | INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix | ||
351 | AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX) | ||
352 | ]) | ||
353 | |||
354 | dnl For backward compatibility. Some Makefiles may be using this. | ||
355 | INTLLIBS="$LIBINTL" | ||
356 | AC_SUBST(INTLLIBS) | ||
357 | |||
358 | dnl Make all documented variables known to autoconf. | ||
359 | AC_SUBST(LIBINTL) | ||
360 | AC_SUBST(LTLIBINTL) | ||
361 | AC_SUBST(POSUB) | ||
362 | ]) | ||
363 | |||
364 | |||
365 | dnl Checks for special options needed on MacOS X. | ||
366 | dnl Defines INTL_MACOSX_LIBS. | ||
367 | AC_DEFUN([gt_INTL_MACOSX], | ||
368 | [ | ||
369 | dnl Check for API introduced in MacOS X 10.2. | ||
370 | AC_CACHE_CHECK([for CFPreferencesCopyAppValue], | ||
371 | gt_cv_func_CFPreferencesCopyAppValue, | ||
372 | [gt_save_LIBS="$LIBS" | ||
373 | LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" | ||
374 | AC_TRY_LINK([#include <CoreFoundation/CFPreferences.h>], | ||
375 | [CFPreferencesCopyAppValue(NULL, NULL)], | ||
376 | [gt_cv_func_CFPreferencesCopyAppValue=yes], | ||
377 | [gt_cv_func_CFPreferencesCopyAppValue=no]) | ||
378 | LIBS="$gt_save_LIBS"]) | ||
379 | if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then | ||
380 | AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], 1, | ||
381 | [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.]) | ||
382 | fi | ||
383 | dnl Check for API introduced in MacOS X 10.3. | ||
384 | AC_CACHE_CHECK([for CFLocaleCopyCurrent], gt_cv_func_CFLocaleCopyCurrent, | ||
385 | [gt_save_LIBS="$LIBS" | ||
386 | LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" | ||
387 | AC_TRY_LINK([#include <CoreFoundation/CFLocale.h>], [CFLocaleCopyCurrent();], | ||
388 | [gt_cv_func_CFLocaleCopyCurrent=yes], | ||
389 | [gt_cv_func_CFLocaleCopyCurrent=no]) | ||
390 | LIBS="$gt_save_LIBS"]) | ||
391 | if test $gt_cv_func_CFLocaleCopyCurrent = yes; then | ||
392 | AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], 1, | ||
393 | [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.]) | ||
394 | fi | ||
395 | INTL_MACOSX_LIBS= | ||
396 | if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then | ||
397 | INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" | ||
398 | fi | ||
399 | AC_SUBST([INTL_MACOSX_LIBS]) | ||
400 | ]) | ||
401 | |||
402 | |||
403 | dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized. | ||
404 | m4_define([gt_NEEDS_INIT], | ||
405 | [ | ||
406 | m4_divert_text([DEFAULTS], [gt_needs=]) | ||
407 | m4_define([gt_NEEDS_INIT], []) | ||
408 | ]) | ||
409 | |||
410 | |||
411 | dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL]) | ||
412 | AC_DEFUN([AM_GNU_GETTEXT_NEED], | ||
413 | [ | ||
414 | m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"]) | ||
415 | ]) | ||
416 | |||
417 | |||
418 | dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) | ||
419 | AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) | ||
diff --git a/gl/m4/glibc2.m4 b/gl/m4/glibc2.m4 new file mode 100644 index 00000000..e8f5bfe6 --- /dev/null +++ b/gl/m4/glibc2.m4 | |||
@@ -0,0 +1,30 @@ | |||
1 | # glibc2.m4 serial 1 | ||
2 | dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | # Test for the GNU C Library, version 2.0 or newer. | ||
8 | # From Bruno Haible. | ||
9 | |||
10 | AC_DEFUN([gt_GLIBC2], | ||
11 | [ | ||
12 | AC_CACHE_CHECK(whether we are using the GNU C Library 2 or newer, | ||
13 | ac_cv_gnu_library_2, | ||
14 | [AC_EGREP_CPP([Lucky GNU user], | ||
15 | [ | ||
16 | #include <features.h> | ||
17 | #ifdef __GNU_LIBRARY__ | ||
18 | #if (__GLIBC__ >= 2) | ||
19 | Lucky GNU user | ||
20 | #endif | ||
21 | #endif | ||
22 | ], | ||
23 | ac_cv_gnu_library_2=yes, | ||
24 | ac_cv_gnu_library_2=no) | ||
25 | ] | ||
26 | ) | ||
27 | AC_SUBST(GLIBC2) | ||
28 | GLIBC2="$ac_cv_gnu_library_2" | ||
29 | ] | ||
30 | ) | ||
diff --git a/gl/m4/glibc21.m4 b/gl/m4/glibc21.m4 new file mode 100644 index 00000000..d95fd986 --- /dev/null +++ b/gl/m4/glibc21.m4 | |||
@@ -0,0 +1,30 @@ | |||
1 | # glibc21.m4 serial 3 | ||
2 | dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | # Test for the GNU C Library, version 2.1 or newer. | ||
8 | # From Bruno Haible. | ||
9 | |||
10 | AC_DEFUN([gl_GLIBC21], | ||
11 | [ | ||
12 | AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, | ||
13 | ac_cv_gnu_library_2_1, | ||
14 | [AC_EGREP_CPP([Lucky GNU user], | ||
15 | [ | ||
16 | #include <features.h> | ||
17 | #ifdef __GNU_LIBRARY__ | ||
18 | #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) | ||
19 | Lucky GNU user | ||
20 | #endif | ||
21 | #endif | ||
22 | ], | ||
23 | ac_cv_gnu_library_2_1=yes, | ||
24 | ac_cv_gnu_library_2_1=no) | ||
25 | ] | ||
26 | ) | ||
27 | AC_SUBST(GLIBC21) | ||
28 | GLIBC21="$ac_cv_gnu_library_2_1" | ||
29 | ] | ||
30 | ) | ||
diff --git a/gl/m4/gnulib-cache.m4 b/gl/m4/gnulib-cache.m4 new file mode 100644 index 00000000..e78c8604 --- /dev/null +++ b/gl/m4/gnulib-cache.m4 | |||
@@ -0,0 +1,30 @@ | |||
1 | # Copyright (C) 2004-2007 Free Software Foundation, Inc. | ||
2 | # | ||
3 | # This file is free software, distributed under the terms of the GNU | ||
4 | # General Public License. As a special exception to the GNU General | ||
5 | # Public License, this file may be distributed as part of a program | ||
6 | # that contains a configuration script generated by Autoconf, under | ||
7 | # the same distribution terms as the rest of that program. | ||
8 | # | ||
9 | # Generated by gnulib-tool. | ||
10 | # | ||
11 | # This file represents the specification of how gnulib-tool is used. | ||
12 | # It acts as a cache: It is written and read by gnulib-tool. | ||
13 | # In projects using CVS, this file is meant to be stored in CVS, | ||
14 | # like the configure.ac and various Makefile.am files. | ||
15 | |||
16 | |||
17 | # Specification in the form of a command-line invocation: | ||
18 | # gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --aux-dir=. --no-libtool --macro-prefix=gl dirname fsusage getaddrinfo gethostname getloadavg getopt gettext mountlist regex vasprintf vsnprintf | ||
19 | |||
20 | # Specification in the form of a few gnulib-tool.m4 macro invocations: | ||
21 | gl_LOCAL_DIR([]) | ||
22 | gl_MODULES([dirname fsusage getaddrinfo gethostname getloadavg getopt gettext mountlist regex vasprintf vsnprintf]) | ||
23 | gl_AVOID([]) | ||
24 | gl_SOURCE_BASE([gl]) | ||
25 | gl_M4_BASE([gl/m4]) | ||
26 | gl_DOC_BASE([doc]) | ||
27 | gl_TESTS_BASE([tests]) | ||
28 | gl_LIB([libgnu]) | ||
29 | gl_MAKEFILE_NAME([]) | ||
30 | gl_MACRO_PREFIX([gl]) | ||
diff --git a/gl/m4/gnulib-common.m4 b/gl/m4/gnulib-common.m4 new file mode 100644 index 00000000..53980108 --- /dev/null +++ b/gl/m4/gnulib-common.m4 | |||
@@ -0,0 +1,22 @@ | |||
1 | # gnulib-common.m4 serial 2 | ||
2 | dnl Copyright (C) 2007 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | # gl_MODULE_INDICATOR([modulename]) | ||
8 | # defines a C macro indicating the presence of the given module. | ||
9 | AC_DEFUN([gl_MODULE_INDICATOR], | ||
10 | [ | ||
11 | AC_DEFINE([GNULIB_]translit([$1],[abcdefghijklmnopqrstuvwxyz./-],[ABCDEFGHIJKLMNOPQRSTUVWXYZ___]), [1], | ||
12 | [Define to 1 when using the gnulib module ]$1[.]) | ||
13 | ]) | ||
14 | |||
15 | # AC_PROG_MKDIR_P | ||
16 | # is a backport of autoconf-2.60's AC_PROG_MKDIR_P. | ||
17 | # Remove this macro when we can assume autoconf >= 2.60. | ||
18 | m4_ifdef([AC_PROG_MKDIR_P], [], [ | ||
19 | AC_DEFUN([AC_PROG_MKDIR_P], | ||
20 | [AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake | ||
21 | MKDIR_P='$(mkdir_p)' | ||
22 | AC_SUBST([MKDIR_P])])]) | ||
diff --git a/gl/m4/gnulib-comp.m4 b/gl/m4/gnulib-comp.m4 new file mode 100644 index 00000000..ed4da7d9 --- /dev/null +++ b/gl/m4/gnulib-comp.m4 | |||
@@ -0,0 +1,326 @@ | |||
1 | # DO NOT EDIT! GENERATED AUTOMATICALLY! | ||
2 | # Copyright (C) 2004-2007 Free Software Foundation, Inc. | ||
3 | # | ||
4 | # This file is free software, distributed under the terms of the GNU | ||
5 | # General Public License. As a special exception to the GNU General | ||
6 | # Public License, this file may be distributed as part of a program | ||
7 | # that contains a configuration script generated by Autoconf, under | ||
8 | # the same distribution terms as the rest of that program. | ||
9 | # | ||
10 | # Generated by gnulib-tool. | ||
11 | # | ||
12 | # This file represents the compiled summary of the specification in | ||
13 | # gnulib-cache.m4. It lists the computed macro invocations that need | ||
14 | # to be invoked from configure.ac. | ||
15 | # In projects using CVS, this file can be treated like other built files. | ||
16 | |||
17 | |||
18 | # This macro should be invoked from ./configure.in, in the section | ||
19 | # "Checks for programs", right after AC_PROG_CC, and certainly before | ||
20 | # any checks for libraries, header files, types and library functions. | ||
21 | AC_DEFUN([gl_EARLY], | ||
22 | [ | ||
23 | m4_pattern_forbid([^gl_[A-Z]])dnl the gnulib macro namespace | ||
24 | m4_pattern_allow([^gl_ES$])dnl a valid locale name | ||
25 | m4_pattern_allow([^gl_LIBOBJS$])dnl a variable | ||
26 | m4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable | ||
27 | AC_REQUIRE([AC_PROG_RANLIB]) | ||
28 | AC_REQUIRE([AC_GNU_SOURCE]) | ||
29 | AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) | ||
30 | AC_REQUIRE([gl_LOCK_EARLY]) | ||
31 | ]) | ||
32 | |||
33 | # This macro should be invoked from ./configure.in, in the section | ||
34 | # "Check for header files, types and library functions". | ||
35 | AC_DEFUN([gl_INIT], | ||
36 | [ | ||
37 | m4_pushdef([AC_LIBOBJ], m4_defn([gl_LIBOBJ])) | ||
38 | m4_pushdef([AC_REPLACE_FUNCS], m4_defn([gl_REPLACE_FUNCS])) | ||
39 | m4_pushdef([AC_LIBSOURCES], m4_defn([gl_LIBSOURCES])) | ||
40 | AM_CONDITIONAL([GL_COND_LIBTOOL], [false]) | ||
41 | gl_cond_libtool=false | ||
42 | gl_libdeps= | ||
43 | gl_ltlibdeps= | ||
44 | gl_source_base='gl' | ||
45 | gl_FUNC_ALLOCA | ||
46 | gl_HEADER_ARPA_INET | ||
47 | gl_C_STRTOD | ||
48 | gl_CLOEXEC | ||
49 | gl_DIRNAME | ||
50 | gl_DOUBLE_SLASH_ROOT | ||
51 | gl_ERROR | ||
52 | gl_EXITFAIL | ||
53 | dnl gl_USE_SYSTEM_EXTENSIONS must be added quite early to configure.ac. | ||
54 | gl_FCNTL_SAFER | ||
55 | gl_MODULE_INDICATOR([fcntl-safer]) | ||
56 | gl_FSUSAGE | ||
57 | gl_GETADDRINFO | ||
58 | gl_FUNC_GETHOSTNAME | ||
59 | gl_GETLOADAVG([$gl_source_base]) | ||
60 | gl_GETOPT | ||
61 | dnl you must add AM_GNU_GETTEXT([external]) or similar to configure.ac. | ||
62 | AM_GNU_GETTEXT_VERSION([0.15]) | ||
63 | gl_INET_NTOP | ||
64 | gl_INLINE | ||
65 | AC_FUNC_MALLOC | ||
66 | gl_MBCHAR | ||
67 | gl_MBITER | ||
68 | gl_FUNC_MEMCHR | ||
69 | gl_MINMAX | ||
70 | gl_MOUNTLIST | ||
71 | gl_HEADER_NETINET_IN | ||
72 | gl_REGEX | ||
73 | gl_SAFE_READ | ||
74 | gl_SAFE_WRITE | ||
75 | gl_SIZE_MAX | ||
76 | gl_FUNC_SNPRINTF | ||
77 | gl_TYPE_SOCKLEN_T | ||
78 | gt_TYPE_SSIZE_T | ||
79 | AM_STDBOOL_H | ||
80 | gl_STDINT_H | ||
81 | gl_STRCASE | ||
82 | gl_FUNC_STRDUP | ||
83 | gl_FUNC_STRNDUP | ||
84 | gl_FUNC_STRNLEN | ||
85 | gl_HEADER_SYS_SOCKET | ||
86 | AC_PROG_MKDIR_P | ||
87 | gl_HEADER_UNISTD | ||
88 | gl_UNISTD_SAFER | ||
89 | gl_FUNC_VASNPRINTF | ||
90 | gl_FUNC_VASPRINTF | ||
91 | gl_FUNC_VSNPRINTF | ||
92 | gl_WCHAR_H | ||
93 | gl_WCTYPE_H | ||
94 | gl_FUNC_WCWIDTH | ||
95 | gl_XALLOC | ||
96 | gl_XSIZE | ||
97 | gl_XSTRNDUP | ||
98 | LIBGNU_LIBDEPS="$gl_libdeps" | ||
99 | AC_SUBST([LIBGNU_LIBDEPS]) | ||
100 | LIBGNU_LTLIBDEPS="$gl_ltlibdeps" | ||
101 | AC_SUBST([LIBGNU_LTLIBDEPS]) | ||
102 | m4_popdef([AC_LIBSOURCES]) | ||
103 | m4_popdef([AC_REPLACE_FUNCS]) | ||
104 | m4_popdef([AC_LIBOBJ]) | ||
105 | AC_CONFIG_COMMANDS_PRE([ | ||
106 | gl_libobjs= | ||
107 | gl_ltlibobjs= | ||
108 | if test -n "$gl_LIBOBJS"; then | ||
109 | # Remove the extension. | ||
110 | sed_drop_objext='s/\.o$//;s/\.obj$//' | ||
111 | for i in `for i in $gl_LIBOBJS; do echo "$i"; done | sed "$sed_drop_objext" | sort | uniq`; do | ||
112 | gl_libobjs="$gl_libobjs $i.$ac_objext" | ||
113 | gl_ltlibobjs="$gl_ltlibobjs $i.lo" | ||
114 | done | ||
115 | fi | ||
116 | AC_SUBST([gl_LIBOBJS], [$gl_libobjs]) | ||
117 | AC_SUBST([gl_LTLIBOBJS], [$gl_ltlibobjs]) | ||
118 | ]) | ||
119 | ]) | ||
120 | |||
121 | # Like AC_LIBOBJ, except that the module name goes | ||
122 | # into gl_LIBOBJS instead of into LIBOBJS. | ||
123 | AC_DEFUN([gl_LIBOBJ], | ||
124 | [gl_LIBOBJS="$gl_LIBOBJS $1.$ac_objext"]) | ||
125 | |||
126 | # Like AC_REPLACE_FUNCS, except that the module name goes | ||
127 | # into gl_LIBOBJS instead of into LIBOBJS. | ||
128 | AC_DEFUN([gl_REPLACE_FUNCS], | ||
129 | [AC_CHECK_FUNCS([$1], , [gl_LIBOBJ($ac_func)])]) | ||
130 | |||
131 | # Like AC_LIBSOURCES, except that it does nothing. | ||
132 | # We rely on EXTRA_lib..._SOURCES instead. | ||
133 | AC_DEFUN([gl_LIBSOURCES], | ||
134 | []) | ||
135 | |||
136 | # This macro records the list of files which have been installed by | ||
137 | # gnulib-tool and may be removed by future gnulib-tool invocations. | ||
138 | AC_DEFUN([gl_FILE_LIST], [ | ||
139 | build-aux/config.rpath | ||
140 | lib/alloca.c | ||
141 | lib/alloca_.h | ||
142 | lib/asnprintf.c | ||
143 | lib/asprintf.c | ||
144 | lib/basename.c | ||
145 | lib/c-strtod.c | ||
146 | lib/c-strtod.h | ||
147 | lib/cloexec.c | ||
148 | lib/cloexec.h | ||
149 | lib/creat-safer.c | ||
150 | lib/dirname.c | ||
151 | lib/dirname.h | ||
152 | lib/dup-safer.c | ||
153 | lib/error.c | ||
154 | lib/error.h | ||
155 | lib/exit.h | ||
156 | lib/exitfail.c | ||
157 | lib/exitfail.h | ||
158 | lib/fcntl--.h | ||
159 | lib/fcntl-safer.h | ||
160 | lib/fd-safer.c | ||
161 | lib/fsusage.c | ||
162 | lib/fsusage.h | ||
163 | lib/full-read.c | ||
164 | lib/full-read.h | ||
165 | lib/full-write.c | ||
166 | lib/full-write.h | ||
167 | lib/gai_strerror.c | ||
168 | lib/getaddrinfo.c | ||
169 | lib/getaddrinfo.h | ||
170 | lib/gethostname.c | ||
171 | lib/getloadavg.c | ||
172 | lib/getopt.c | ||
173 | lib/getopt1.c | ||
174 | lib/getopt_.h | ||
175 | lib/getopt_int.h | ||
176 | lib/gettext.h | ||
177 | lib/inet_ntop.c | ||
178 | lib/inet_ntop.h | ||
179 | lib/intprops.h | ||
180 | lib/malloc.c | ||
181 | lib/mbchar.c | ||
182 | lib/mbchar.h | ||
183 | lib/mbuiter.h | ||
184 | lib/memchr.c | ||
185 | lib/minmax.h | ||
186 | lib/mountlist.c | ||
187 | lib/mountlist.h | ||
188 | lib/open-safer.c | ||
189 | lib/pipe-safer.c | ||
190 | lib/printf-args.c | ||
191 | lib/printf-args.h | ||
192 | lib/printf-parse.c | ||
193 | lib/printf-parse.h | ||
194 | lib/regcomp.c | ||
195 | lib/regex.c | ||
196 | lib/regex.h | ||
197 | lib/regex_internal.c | ||
198 | lib/regex_internal.h | ||
199 | lib/regexec.c | ||
200 | lib/safe-read.c | ||
201 | lib/safe-read.h | ||
202 | lib/safe-write.c | ||
203 | lib/safe-write.h | ||
204 | lib/size_max.h | ||
205 | lib/snprintf.c | ||
206 | lib/snprintf.h | ||
207 | lib/socket_.h | ||
208 | lib/stdbool_.h | ||
209 | lib/stdint_.h | ||
210 | lib/strcase.h | ||
211 | lib/strcasecmp.c | ||
212 | lib/strdup.c | ||
213 | lib/strdup.h | ||
214 | lib/stripslash.c | ||
215 | lib/strncasecmp.c | ||
216 | lib/strndup.c | ||
217 | lib/strndup.h | ||
218 | lib/strnlen.c | ||
219 | lib/strnlen.h | ||
220 | lib/strnlen1.c | ||
221 | lib/strnlen1.h | ||
222 | lib/unistd--.h | ||
223 | lib/unistd-safer.h | ||
224 | lib/unistd_.h | ||
225 | lib/vasnprintf.c | ||
226 | lib/vasnprintf.h | ||
227 | lib/vasprintf.c | ||
228 | lib/vasprintf.h | ||
229 | lib/vsnprintf.c | ||
230 | lib/vsnprintf.h | ||
231 | lib/wchar_.h | ||
232 | lib/wctype_.h | ||
233 | lib/wcwidth.h | ||
234 | lib/xalloc-die.c | ||
235 | lib/xalloc.h | ||
236 | lib/xmalloc.c | ||
237 | lib/xsize.h | ||
238 | lib/xstrndup.c | ||
239 | lib/xstrndup.h | ||
240 | m4/absolute-header.m4 | ||
241 | m4/alloca.m4 | ||
242 | m4/arpa_inet_h.m4 | ||
243 | m4/c-strtod.m4 | ||
244 | m4/cloexec.m4 | ||
245 | m4/codeset.m4 | ||
246 | m4/dirname.m4 | ||
247 | m4/dos.m4 | ||
248 | m4/double-slash-root.m4 | ||
249 | m4/eoverflow.m4 | ||
250 | m4/error.m4 | ||
251 | m4/exitfail.m4 | ||
252 | m4/extensions.m4 | ||
253 | m4/fcntl-safer.m4 | ||
254 | m4/fstypename.m4 | ||
255 | m4/fsusage.m4 | ||
256 | m4/getaddrinfo.m4 | ||
257 | m4/gethostname.m4 | ||
258 | m4/getloadavg.m4 | ||
259 | m4/getopt.m4 | ||
260 | m4/gettext.m4 | ||
261 | m4/glibc2.m4 | ||
262 | m4/glibc21.m4 | ||
263 | m4/gnulib-common.m4 | ||
264 | m4/iconv.m4 | ||
265 | m4/inet_ntop.m4 | ||
266 | m4/inline.m4 | ||
267 | m4/intdiv0.m4 | ||
268 | m4/intl.m4 | ||
269 | m4/intldir.m4 | ||
270 | m4/intmax.m4 | ||
271 | m4/intmax_t.m4 | ||
272 | m4/inttypes-pri.m4 | ||
273 | m4/inttypes_h.m4 | ||
274 | m4/lcmessage.m4 | ||
275 | m4/lib-ld.m4 | ||
276 | m4/lib-link.m4 | ||
277 | m4/lib-prefix.m4 | ||
278 | m4/lock.m4 | ||
279 | m4/longdouble.m4 | ||
280 | m4/longlong.m4 | ||
281 | m4/ls-mntd-fs.m4 | ||
282 | m4/mbchar.m4 | ||
283 | m4/mbiter.m4 | ||
284 | m4/mbrtowc.m4 | ||
285 | m4/memchr.m4 | ||
286 | m4/minmax.m4 | ||
287 | m4/mountlist.m4 | ||
288 | m4/netinet_in_h.m4 | ||
289 | m4/nls.m4 | ||
290 | m4/onceonly_2_57.m4 | ||
291 | m4/po.m4 | ||
292 | m4/printf-posix.m4 | ||
293 | m4/progtest.m4 | ||
294 | m4/regex.m4 | ||
295 | m4/safe-read.m4 | ||
296 | m4/safe-write.m4 | ||
297 | m4/size_max.m4 | ||
298 | m4/snprintf.m4 | ||
299 | m4/socklen.m4 | ||
300 | m4/sockpfaf.m4 | ||
301 | m4/ssize_t.m4 | ||
302 | m4/stdbool.m4 | ||
303 | m4/stdint.m4 | ||
304 | m4/stdint_h.m4 | ||
305 | m4/strcase.m4 | ||
306 | m4/strdup.m4 | ||
307 | m4/strndup.m4 | ||
308 | m4/strnlen.m4 | ||
309 | m4/sys_socket_h.m4 | ||
310 | m4/uintmax_t.m4 | ||
311 | m4/ulonglong.m4 | ||
312 | m4/unistd-safer.m4 | ||
313 | m4/unistd_h.m4 | ||
314 | m4/vasnprintf.m4 | ||
315 | m4/vasprintf.m4 | ||
316 | m4/visibility.m4 | ||
317 | m4/vsnprintf.m4 | ||
318 | m4/wchar.m4 | ||
319 | m4/wchar_t.m4 | ||
320 | m4/wctype.m4 | ||
321 | m4/wcwidth.m4 | ||
322 | m4/wint_t.m4 | ||
323 | m4/xalloc.m4 | ||
324 | m4/xsize.m4 | ||
325 | m4/xstrndup.m4 | ||
326 | ]) | ||
diff --git a/gl/m4/gnulib-tool.m4 b/gl/m4/gnulib-tool.m4 new file mode 100644 index 00000000..ef593203 --- /dev/null +++ b/gl/m4/gnulib-tool.m4 | |||
@@ -0,0 +1,33 @@ | |||
1 | # gnulib-tool.m4 serial 1 | ||
2 | dnl Copyright (C) 2004-2005 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl The following macros need not be invoked explicitly. | ||
8 | dnl Invoking them does nothing except to declare default arguments | ||
9 | dnl for "gnulib-tool --import". | ||
10 | |||
11 | dnl Usage: gl_MODULES([module1 module2 ...]) | ||
12 | AC_DEFUN([gl_MODULES], []) | ||
13 | |||
14 | dnl Usage: gl_AVOID([module1 module2 ...]) | ||
15 | AC_DEFUN([gl_AVOID], []) | ||
16 | |||
17 | dnl Usage: gl_SOURCE_BASE([DIR]) | ||
18 | AC_DEFUN([gl_SOURCE_BASE], []) | ||
19 | |||
20 | dnl Usage: gl_M4_BASE([DIR]) | ||
21 | AC_DEFUN([gl_M4_BASE], []) | ||
22 | |||
23 | dnl Usage: gl_LIB([LIBNAME]) | ||
24 | AC_DEFUN([gl_LIB], []) | ||
25 | |||
26 | dnl Usage: gl_LGPL | ||
27 | AC_DEFUN([gl_LGPL], []) | ||
28 | |||
29 | dnl Usage: gl_LIBTOOL | ||
30 | AC_DEFUN([gl_LIBTOOL], []) | ||
31 | |||
32 | dnl Usage: gl_MACRO_PREFIX([PREFIX]) | ||
33 | AC_DEFUN([gl_MACRO_PREFIX], []) | ||
diff --git a/gl/m4/iconv.m4 b/gl/m4/iconv.m4 new file mode 100644 index 00000000..654c4158 --- /dev/null +++ b/gl/m4/iconv.m4 | |||
@@ -0,0 +1,101 @@ | |||
1 | # iconv.m4 serial AM4 (gettext-0.11.3) | ||
2 | dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | |||
9 | AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], | ||
10 | [ | ||
11 | dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. | ||
12 | AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) | ||
13 | AC_REQUIRE([AC_LIB_RPATH]) | ||
14 | |||
15 | dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV | ||
16 | dnl accordingly. | ||
17 | AC_LIB_LINKFLAGS_BODY([iconv]) | ||
18 | ]) | ||
19 | |||
20 | AC_DEFUN([AM_ICONV_LINK], | ||
21 | [ | ||
22 | dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and | ||
23 | dnl those with the standalone portable GNU libiconv installed). | ||
24 | |||
25 | dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV | ||
26 | dnl accordingly. | ||
27 | AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) | ||
28 | |||
29 | dnl Add $INCICONV to CPPFLAGS before performing the following checks, | ||
30 | dnl because if the user has installed libiconv and not disabled its use | ||
31 | dnl via --without-libiconv-prefix, he wants to use it. The first | ||
32 | dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. | ||
33 | am_save_CPPFLAGS="$CPPFLAGS" | ||
34 | AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) | ||
35 | |||
36 | AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ | ||
37 | am_cv_func_iconv="no, consider installing GNU libiconv" | ||
38 | am_cv_lib_iconv=no | ||
39 | AC_TRY_LINK([#include <stdlib.h> | ||
40 | #include <iconv.h>], | ||
41 | [iconv_t cd = iconv_open("",""); | ||
42 | iconv(cd,NULL,NULL,NULL,NULL); | ||
43 | iconv_close(cd);], | ||
44 | am_cv_func_iconv=yes) | ||
45 | if test "$am_cv_func_iconv" != yes; then | ||
46 | am_save_LIBS="$LIBS" | ||
47 | LIBS="$LIBS $LIBICONV" | ||
48 | AC_TRY_LINK([#include <stdlib.h> | ||
49 | #include <iconv.h>], | ||
50 | [iconv_t cd = iconv_open("",""); | ||
51 | iconv(cd,NULL,NULL,NULL,NULL); | ||
52 | iconv_close(cd);], | ||
53 | am_cv_lib_iconv=yes | ||
54 | am_cv_func_iconv=yes) | ||
55 | LIBS="$am_save_LIBS" | ||
56 | fi | ||
57 | ]) | ||
58 | if test "$am_cv_func_iconv" = yes; then | ||
59 | AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) | ||
60 | fi | ||
61 | if test "$am_cv_lib_iconv" = yes; then | ||
62 | AC_MSG_CHECKING([how to link with libiconv]) | ||
63 | AC_MSG_RESULT([$LIBICONV]) | ||
64 | else | ||
65 | dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV | ||
66 | dnl either. | ||
67 | CPPFLAGS="$am_save_CPPFLAGS" | ||
68 | LIBICONV= | ||
69 | LTLIBICONV= | ||
70 | fi | ||
71 | AC_SUBST(LIBICONV) | ||
72 | AC_SUBST(LTLIBICONV) | ||
73 | ]) | ||
74 | |||
75 | AC_DEFUN([AM_ICONV], | ||
76 | [ | ||
77 | AM_ICONV_LINK | ||
78 | if test "$am_cv_func_iconv" = yes; then | ||
79 | AC_MSG_CHECKING([for iconv declaration]) | ||
80 | AC_CACHE_VAL(am_cv_proto_iconv, [ | ||
81 | AC_TRY_COMPILE([ | ||
82 | #include <stdlib.h> | ||
83 | #include <iconv.h> | ||
84 | extern | ||
85 | #ifdef __cplusplus | ||
86 | "C" | ||
87 | #endif | ||
88 | #if defined(__STDC__) || defined(__cplusplus) | ||
89 | size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); | ||
90 | #else | ||
91 | size_t iconv(); | ||
92 | #endif | ||
93 | ], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") | ||
94 | am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) | ||
95 | am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` | ||
96 | AC_MSG_RESULT([$]{ac_t:- | ||
97 | }[$]am_cv_proto_iconv) | ||
98 | AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, | ||
99 | [Define as const if the declaration of iconv() needs const.]) | ||
100 | fi | ||
101 | ]) | ||
diff --git a/gl/m4/inet_ntop.m4 b/gl/m4/inet_ntop.m4 new file mode 100644 index 00000000..bb02d229 --- /dev/null +++ b/gl/m4/inet_ntop.m4 | |||
@@ -0,0 +1,19 @@ | |||
1 | # inet_ntop.m4 serial 3 | ||
2 | dnl Copyright (C) 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_INET_NTOP], | ||
8 | [ | ||
9 | AC_REPLACE_FUNCS(inet_ntop) | ||
10 | gl_PREREQ_INET_NTOP | ||
11 | ]) | ||
12 | |||
13 | # Prerequisites of lib/inet_ntop.h and lib/inet_ntop.c. | ||
14 | AC_DEFUN([gl_PREREQ_INET_NTOP], [ | ||
15 | AC_CHECK_HEADERS_ONCE([netinet/in.h arpa/inet.h]) | ||
16 | AC_CHECK_DECLS([inet_ntop],,,[#include <arpa/inet.h>]) | ||
17 | AC_REQUIRE([gl_SOCKET_FAMILIES]) | ||
18 | AC_REQUIRE([AC_C_RESTRICT]) | ||
19 | ]) | ||
diff --git a/gl/m4/inline.m4 b/gl/m4/inline.m4 new file mode 100644 index 00000000..a07076cd --- /dev/null +++ b/gl/m4/inline.m4 | |||
@@ -0,0 +1,40 @@ | |||
1 | # inline.m4 serial 3 | ||
2 | dnl Copyright (C) 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl Test for the 'inline' keyword or equivalent. | ||
8 | dnl Define 'inline' to a supported equivalent, or to nothing if not supported, | ||
9 | dnl like AC_C_INLINE does. Also, define HAVE_INLINE if 'inline' or an | ||
10 | dnl equivalent is effectively supported, i.e. if the compiler is likely to | ||
11 | dnl drop unused 'static inline' functions. | ||
12 | AC_DEFUN([gl_INLINE], | ||
13 | [ | ||
14 | AC_REQUIRE([AC_C_INLINE]) | ||
15 | AC_CACHE_CHECK([whether the compiler generally respects inline], | ||
16 | [gl_cv_c_inline_effective], | ||
17 | [if test $ac_cv_c_inline = no; then | ||
18 | gl_cv_c_inline_effective=no | ||
19 | else | ||
20 | dnl GCC defines __NO_INLINE__ if not optimizing or if -fno-inline is | ||
21 | dnl specified. | ||
22 | dnl Use AC_COMPILE_IFELSE here, not AC_EGREP_CPP, because the result | ||
23 | dnl depends on optimization flags, which can be in CFLAGS. | ||
24 | dnl (AC_EGREP_CPP looks only at the CPPFLAGS.) | ||
25 | AC_COMPILE_IFELSE( | ||
26 | [AC_LANG_PROGRAM([[]], | ||
27 | [[#ifdef __NO_INLINE__ | ||
28 | #error "inline is not effective" | ||
29 | #endif]])], | ||
30 | [gl_cv_c_inline_effective=yes], | ||
31 | [gl_cv_c_inline_effective=no]) | ||
32 | fi | ||
33 | ]) | ||
34 | if test $gl_cv_c_inline_effective = yes; then | ||
35 | AC_DEFINE([HAVE_INLINE], 1, | ||
36 | [Define to 1 if the compiler supports one of the keywords | ||
37 | 'inline', '__inline__', '__inline' and effectively inlines | ||
38 | functions marked as such.]) | ||
39 | fi | ||
40 | ]) | ||
diff --git a/gl/m4/intdiv0.m4 b/gl/m4/intdiv0.m4 new file mode 100644 index 00000000..b8d78176 --- /dev/null +++ b/gl/m4/intdiv0.m4 | |||
@@ -0,0 +1,70 @@ | |||
1 | # intdiv0.m4 serial 1 (gettext-0.11.3) | ||
2 | dnl Copyright (C) 2002 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | |||
9 | AC_DEFUN([gt_INTDIV0], | ||
10 | [ | ||
11 | AC_REQUIRE([AC_PROG_CC])dnl | ||
12 | AC_REQUIRE([AC_CANONICAL_HOST])dnl | ||
13 | |||
14 | AC_CACHE_CHECK([whether integer division by zero raises SIGFPE], | ||
15 | gt_cv_int_divbyzero_sigfpe, | ||
16 | [ | ||
17 | AC_TRY_RUN([ | ||
18 | #include <stdlib.h> | ||
19 | #include <signal.h> | ||
20 | |||
21 | static void | ||
22 | #ifdef __cplusplus | ||
23 | sigfpe_handler (int sig) | ||
24 | #else | ||
25 | sigfpe_handler (sig) int sig; | ||
26 | #endif | ||
27 | { | ||
28 | /* Exit with code 0 if SIGFPE, with code 1 if any other signal. */ | ||
29 | exit (sig != SIGFPE); | ||
30 | } | ||
31 | |||
32 | int x = 1; | ||
33 | int y = 0; | ||
34 | int z; | ||
35 | int nan; | ||
36 | |||
37 | int main () | ||
38 | { | ||
39 | signal (SIGFPE, sigfpe_handler); | ||
40 | /* IRIX and AIX (when "xlc -qcheck" is used) yield signal SIGTRAP. */ | ||
41 | #if (defined (__sgi) || defined (_AIX)) && defined (SIGTRAP) | ||
42 | signal (SIGTRAP, sigfpe_handler); | ||
43 | #endif | ||
44 | /* Linux/SPARC yields signal SIGILL. */ | ||
45 | #if defined (__sparc__) && defined (__linux__) | ||
46 | signal (SIGILL, sigfpe_handler); | ||
47 | #endif | ||
48 | |||
49 | z = x / y; | ||
50 | nan = y / y; | ||
51 | exit (1); | ||
52 | } | ||
53 | ], gt_cv_int_divbyzero_sigfpe=yes, gt_cv_int_divbyzero_sigfpe=no, | ||
54 | [ | ||
55 | # Guess based on the CPU. | ||
56 | case "$host_cpu" in | ||
57 | alpha* | i[34567]86 | m68k | s390*) | ||
58 | gt_cv_int_divbyzero_sigfpe="guessing yes";; | ||
59 | *) | ||
60 | gt_cv_int_divbyzero_sigfpe="guessing no";; | ||
61 | esac | ||
62 | ]) | ||
63 | ]) | ||
64 | case "$gt_cv_int_divbyzero_sigfpe" in | ||
65 | *yes) value=1;; | ||
66 | *) value=0;; | ||
67 | esac | ||
68 | AC_DEFINE_UNQUOTED(INTDIV0_RAISES_SIGFPE, $value, | ||
69 | [Define if integer division by zero raises signal SIGFPE.]) | ||
70 | ]) | ||
diff --git a/gl/m4/intl.m4 b/gl/m4/intl.m4 new file mode 100644 index 00000000..dcefb118 --- /dev/null +++ b/gl/m4/intl.m4 | |||
@@ -0,0 +1,259 @@ | |||
1 | # intl.m4 serial 3 (gettext-0.16) | ||
2 | dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | dnl | ||
7 | dnl This file can can be used in projects which are not available under | ||
8 | dnl the GNU General Public License or the GNU Library General Public | ||
9 | dnl License but which still want to provide support for the GNU gettext | ||
10 | dnl functionality. | ||
11 | dnl Please note that the actual code of the GNU gettext library is covered | ||
12 | dnl by the GNU Library General Public License, and the rest of the GNU | ||
13 | dnl gettext package package is covered by the GNU General Public License. | ||
14 | dnl They are *not* in the public domain. | ||
15 | |||
16 | dnl Authors: | ||
17 | dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. | ||
18 | dnl Bruno Haible <haible@clisp.cons.org>, 2000-2006. | ||
19 | |||
20 | AC_PREREQ(2.52) | ||
21 | |||
22 | dnl Checks for all prerequisites of the intl subdirectory, | ||
23 | dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, | ||
24 | dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. | ||
25 | AC_DEFUN([AM_INTL_SUBDIR], | ||
26 | [ | ||
27 | AC_REQUIRE([AC_PROG_INSTALL])dnl | ||
28 | AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake | ||
29 | AC_REQUIRE([AC_PROG_CC])dnl | ||
30 | AC_REQUIRE([AC_CANONICAL_HOST])dnl | ||
31 | AC_REQUIRE([gt_GLIBC2])dnl | ||
32 | AC_REQUIRE([AC_PROG_RANLIB])dnl | ||
33 | AC_REQUIRE([gl_VISIBILITY])dnl | ||
34 | AC_REQUIRE([gt_INTL_SUBDIR_CORE])dnl | ||
35 | AC_REQUIRE([AC_TYPE_LONG_LONG_INT])dnl | ||
36 | AC_REQUIRE([gt_TYPE_LONGDOUBLE])dnl | ||
37 | AC_REQUIRE([gt_TYPE_WCHAR_T])dnl | ||
38 | AC_REQUIRE([gt_TYPE_WINT_T])dnl | ||
39 | AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) | ||
40 | AC_REQUIRE([gt_TYPE_INTMAX_T]) | ||
41 | AC_REQUIRE([gt_PRINTF_POSIX]) | ||
42 | AC_REQUIRE([gl_GLIBC21])dnl | ||
43 | AC_REQUIRE([gl_XSIZE])dnl | ||
44 | AC_REQUIRE([gt_INTL_MACOSX])dnl | ||
45 | |||
46 | AC_CHECK_TYPE([ptrdiff_t], , | ||
47 | [AC_DEFINE([ptrdiff_t], [long], | ||
48 | [Define as the type of the result of subtracting two pointers, if the system doesn't define it.]) | ||
49 | ]) | ||
50 | AC_CHECK_HEADERS([stddef.h stdlib.h string.h]) | ||
51 | AC_CHECK_FUNCS([asprintf fwprintf putenv setenv setlocale snprintf wcslen]) | ||
52 | |||
53 | dnl Use the _snprintf function only if it is declared (because on NetBSD it | ||
54 | dnl is defined as a weak alias of snprintf; we prefer to use the latter). | ||
55 | gt_CHECK_DECL(_snprintf, [#include <stdio.h>]) | ||
56 | gt_CHECK_DECL(_snwprintf, [#include <stdio.h>]) | ||
57 | |||
58 | dnl Use the *_unlocked functions only if they are declared. | ||
59 | dnl (because some of them were defined without being declared in Solaris | ||
60 | dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built | ||
61 | dnl on Solaris 2.5.1 to run on Solaris 2.6). | ||
62 | dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. | ||
63 | gt_CHECK_DECL(getc_unlocked, [#include <stdio.h>]) | ||
64 | |||
65 | case $gt_cv_func_printf_posix in | ||
66 | *yes) HAVE_POSIX_PRINTF=1 ;; | ||
67 | *) HAVE_POSIX_PRINTF=0 ;; | ||
68 | esac | ||
69 | AC_SUBST([HAVE_POSIX_PRINTF]) | ||
70 | if test "$ac_cv_func_asprintf" = yes; then | ||
71 | HAVE_ASPRINTF=1 | ||
72 | else | ||
73 | HAVE_ASPRINTF=0 | ||
74 | fi | ||
75 | AC_SUBST([HAVE_ASPRINTF]) | ||
76 | if test "$ac_cv_func_snprintf" = yes; then | ||
77 | HAVE_SNPRINTF=1 | ||
78 | else | ||
79 | HAVE_SNPRINTF=0 | ||
80 | fi | ||
81 | AC_SUBST([HAVE_SNPRINTF]) | ||
82 | if test "$ac_cv_func_wprintf" = yes; then | ||
83 | HAVE_WPRINTF=1 | ||
84 | else | ||
85 | HAVE_WPRINTF=0 | ||
86 | fi | ||
87 | AC_SUBST([HAVE_WPRINTF]) | ||
88 | |||
89 | AM_LANGINFO_CODESET | ||
90 | gt_LC_MESSAGES | ||
91 | |||
92 | dnl Compilation on mingw and Cygwin needs special Makefile rules, because | ||
93 | dnl 1. when we install a shared library, we must arrange to export | ||
94 | dnl auxiliary pointer variables for every exported variable, | ||
95 | dnl 2. when we install a shared library and a static library simultaneously, | ||
96 | dnl the include file specifies __declspec(dllimport) and therefore we | ||
97 | dnl must arrange to define the auxiliary pointer variables for the | ||
98 | dnl exported variables _also_ in the static library. | ||
99 | if test "$enable_shared" = yes; then | ||
100 | case "$host_os" in | ||
101 | cygwin*) is_woe32dll=yes ;; | ||
102 | *) is_woe32dll=no ;; | ||
103 | esac | ||
104 | else | ||
105 | is_woe32dll=no | ||
106 | fi | ||
107 | WOE32DLL=$is_woe32dll | ||
108 | AC_SUBST([WOE32DLL]) | ||
109 | |||
110 | dnl Rename some macros and functions used for locking. | ||
111 | AH_BOTTOM([ | ||
112 | #define __libc_lock_t gl_lock_t | ||
113 | #define __libc_lock_define gl_lock_define | ||
114 | #define __libc_lock_define_initialized gl_lock_define_initialized | ||
115 | #define __libc_lock_init gl_lock_init | ||
116 | #define __libc_lock_lock gl_lock_lock | ||
117 | #define __libc_lock_unlock gl_lock_unlock | ||
118 | #define __libc_lock_recursive_t gl_recursive_lock_t | ||
119 | #define __libc_lock_define_recursive gl_recursive_lock_define | ||
120 | #define __libc_lock_define_initialized_recursive gl_recursive_lock_define_initialized | ||
121 | #define __libc_lock_init_recursive gl_recursive_lock_init | ||
122 | #define __libc_lock_lock_recursive gl_recursive_lock_lock | ||
123 | #define __libc_lock_unlock_recursive gl_recursive_lock_unlock | ||
124 | #define glthread_in_use libintl_thread_in_use | ||
125 | #define glthread_lock_init libintl_lock_init | ||
126 | #define glthread_lock_lock libintl_lock_lock | ||
127 | #define glthread_lock_unlock libintl_lock_unlock | ||
128 | #define glthread_lock_destroy libintl_lock_destroy | ||
129 | #define glthread_rwlock_init libintl_rwlock_init | ||
130 | #define glthread_rwlock_rdlock libintl_rwlock_rdlock | ||
131 | #define glthread_rwlock_wrlock libintl_rwlock_wrlock | ||
132 | #define glthread_rwlock_unlock libintl_rwlock_unlock | ||
133 | #define glthread_rwlock_destroy libintl_rwlock_destroy | ||
134 | #define glthread_recursive_lock_init libintl_recursive_lock_init | ||
135 | #define glthread_recursive_lock_lock libintl_recursive_lock_lock | ||
136 | #define glthread_recursive_lock_unlock libintl_recursive_lock_unlock | ||
137 | #define glthread_recursive_lock_destroy libintl_recursive_lock_destroy | ||
138 | #define glthread_once libintl_once | ||
139 | #define glthread_once_call libintl_once_call | ||
140 | #define glthread_once_singlethreaded libintl_once_singlethreaded | ||
141 | ]) | ||
142 | ]) | ||
143 | |||
144 | |||
145 | dnl Checks for the core files of the intl subdirectory: | ||
146 | dnl dcigettext.c | ||
147 | dnl eval-plural.h | ||
148 | dnl explodename.c | ||
149 | dnl finddomain.c | ||
150 | dnl gettextP.h | ||
151 | dnl gmo.h | ||
152 | dnl hash-string.h hash-string.c | ||
153 | dnl l10nflist.c | ||
154 | dnl libgnuintl.h.in (except the *printf stuff) | ||
155 | dnl loadinfo.h | ||
156 | dnl loadmsgcat.c | ||
157 | dnl localealias.c | ||
158 | dnl log.c | ||
159 | dnl plural-exp.h plural-exp.c | ||
160 | dnl plural.y | ||
161 | dnl Used by libglocale. | ||
162 | AC_DEFUN([gt_INTL_SUBDIR_CORE], | ||
163 | [ | ||
164 | AC_REQUIRE([AC_C_INLINE])dnl | ||
165 | AC_REQUIRE([AC_TYPE_SIZE_T])dnl | ||
166 | AC_REQUIRE([gl_AC_HEADER_STDINT_H]) | ||
167 | AC_REQUIRE([AC_FUNC_ALLOCA])dnl | ||
168 | AC_REQUIRE([AC_FUNC_MMAP])dnl | ||
169 | AC_REQUIRE([gt_INTDIV0])dnl | ||
170 | AC_REQUIRE([gl_AC_TYPE_UINTMAX_T])dnl | ||
171 | AC_REQUIRE([gt_INTTYPES_PRI])dnl | ||
172 | AC_REQUIRE([gl_LOCK])dnl | ||
173 | |||
174 | AC_TRY_LINK( | ||
175 | [int foo (int a) { a = __builtin_expect (a, 10); return a == 10 ? 0 : 1; }], | ||
176 | [], | ||
177 | [AC_DEFINE([HAVE_BUILTIN_EXPECT], 1, | ||
178 | [Define to 1 if the compiler understands __builtin_expect.])]) | ||
179 | |||
180 | AC_CHECK_HEADERS([argz.h inttypes.h limits.h unistd.h sys/param.h]) | ||
181 | AC_CHECK_FUNCS([getcwd getegid geteuid getgid getuid mempcpy munmap \ | ||
182 | stpcpy strcasecmp strdup strtoul tsearch argz_count argz_stringify \ | ||
183 | argz_next __fsetlocking]) | ||
184 | |||
185 | dnl Use the *_unlocked functions only if they are declared. | ||
186 | dnl (because some of them were defined without being declared in Solaris | ||
187 | dnl 2.5.1 but were removed in Solaris 2.6, whereas we want binaries built | ||
188 | dnl on Solaris 2.5.1 to run on Solaris 2.6). | ||
189 | dnl Don't use AC_CHECK_DECLS because it isn't supported in autoconf-2.13. | ||
190 | gt_CHECK_DECL(feof_unlocked, [#include <stdio.h>]) | ||
191 | gt_CHECK_DECL(fgets_unlocked, [#include <stdio.h>]) | ||
192 | |||
193 | AM_ICONV | ||
194 | |||
195 | dnl glibc >= 2.4 has a NL_LOCALE_NAME macro when _GNU_SOURCE is defined, | ||
196 | dnl and a _NL_LOCALE_NAME macro always. | ||
197 | AC_CACHE_CHECK([for NL_LOCALE_NAME macro], gt_cv_nl_locale_name, | ||
198 | [AC_TRY_LINK([#include <langinfo.h> | ||
199 | #include <locale.h>], | ||
200 | [char* cs = nl_langinfo(_NL_LOCALE_NAME(LC_MESSAGES));], | ||
201 | gt_cv_nl_locale_name=yes, | ||
202 | gt_cv_nl_locale_name=no) | ||
203 | ]) | ||
204 | if test $gt_cv_nl_locale_name = yes; then | ||
205 | AC_DEFINE(HAVE_NL_LOCALE_NAME, 1, | ||
206 | [Define if you have <langinfo.h> and it defines the NL_LOCALE_NAME macro if _GNU_SOURCE is defined.]) | ||
207 | fi | ||
208 | |||
209 | dnl intl/plural.c is generated from intl/plural.y. It requires bison, | ||
210 | dnl because plural.y uses bison specific features. It requires at least | ||
211 | dnl bison-1.26 because earlier versions generate a plural.c that doesn't | ||
212 | dnl compile. | ||
213 | dnl bison is only needed for the maintainer (who touches plural.y). But in | ||
214 | dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put | ||
215 | dnl the rule in general Makefile. Now, some people carelessly touch the | ||
216 | dnl files or have a broken "make" program, hence the plural.c rule will | ||
217 | dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not | ||
218 | dnl present or too old. | ||
219 | AC_CHECK_PROGS([INTLBISON], [bison]) | ||
220 | if test -z "$INTLBISON"; then | ||
221 | ac_verc_fail=yes | ||
222 | else | ||
223 | dnl Found it, now check the version. | ||
224 | AC_MSG_CHECKING([version of bison]) | ||
225 | changequote(<<,>>)dnl | ||
226 | ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` | ||
227 | case $ac_prog_version in | ||
228 | '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; | ||
229 | 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) | ||
230 | changequote([,])dnl | ||
231 | ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; | ||
232 | *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; | ||
233 | esac | ||
234 | AC_MSG_RESULT([$ac_prog_version]) | ||
235 | fi | ||
236 | if test $ac_verc_fail = yes; then | ||
237 | INTLBISON=: | ||
238 | fi | ||
239 | ]) | ||
240 | |||
241 | |||
242 | dnl gt_CHECK_DECL(FUNC, INCLUDES) | ||
243 | dnl Check whether a function is declared. | ||
244 | AC_DEFUN([gt_CHECK_DECL], | ||
245 | [ | ||
246 | AC_CACHE_CHECK([whether $1 is declared], ac_cv_have_decl_$1, | ||
247 | [AC_TRY_COMPILE([$2], [ | ||
248 | #ifndef $1 | ||
249 | char *p = (char *) $1; | ||
250 | #endif | ||
251 | ], ac_cv_have_decl_$1=yes, ac_cv_have_decl_$1=no)]) | ||
252 | if test $ac_cv_have_decl_$1 = yes; then | ||
253 | gt_value=1 | ||
254 | else | ||
255 | gt_value=0 | ||
256 | fi | ||
257 | AC_DEFINE_UNQUOTED([HAVE_DECL_]translit($1, [a-z], [A-Z]), [$gt_value], | ||
258 | [Define to 1 if you have the declaration of `$1', and to 0 if you don't.]) | ||
259 | ]) | ||
diff --git a/gl/m4/intldir.m4 b/gl/m4/intldir.m4 new file mode 100644 index 00000000..7a28843f --- /dev/null +++ b/gl/m4/intldir.m4 | |||
@@ -0,0 +1,19 @@ | |||
1 | # intldir.m4 serial 1 (gettext-0.16) | ||
2 | dnl Copyright (C) 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | dnl | ||
7 | dnl This file can can be used in projects which are not available under | ||
8 | dnl the GNU General Public License or the GNU Library General Public | ||
9 | dnl License but which still want to provide support for the GNU gettext | ||
10 | dnl functionality. | ||
11 | dnl Please note that the actual code of the GNU gettext library is covered | ||
12 | dnl by the GNU Library General Public License, and the rest of the GNU | ||
13 | dnl gettext package package is covered by the GNU General Public License. | ||
14 | dnl They are *not* in the public domain. | ||
15 | |||
16 | AC_PREREQ(2.52) | ||
17 | |||
18 | dnl Tells the AM_GNU_GETTEXT macro to consider an intl/ directory. | ||
19 | AC_DEFUN([AM_GNU_GETTEXT_INTL_SUBDIR], []) | ||
diff --git a/gl/m4/intmax.m4 b/gl/m4/intmax.m4 new file mode 100644 index 00000000..ce7a8a49 --- /dev/null +++ b/gl/m4/intmax.m4 | |||
@@ -0,0 +1,33 @@ | |||
1 | # intmax.m4 serial 3 (gettext-0.16) | ||
2 | dnl Copyright (C) 2002-2005 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | dnl Test whether the system has the 'intmax_t' type, but don't attempt to | ||
9 | dnl find a replacement if it is lacking. | ||
10 | |||
11 | AC_DEFUN([gt_TYPE_INTMAX_T], | ||
12 | [ | ||
13 | AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) | ||
14 | AC_REQUIRE([gl_AC_HEADER_STDINT_H]) | ||
15 | AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t, | ||
16 | [AC_TRY_COMPILE([ | ||
17 | #include <stddef.h> | ||
18 | #include <stdlib.h> | ||
19 | #if HAVE_STDINT_H_WITH_UINTMAX | ||
20 | #include <stdint.h> | ||
21 | #endif | ||
22 | #if HAVE_INTTYPES_H_WITH_UINTMAX | ||
23 | #include <inttypes.h> | ||
24 | #endif | ||
25 | ], [intmax_t x = -1; | ||
26 | return !x;], | ||
27 | gt_cv_c_intmax_t=yes, | ||
28 | gt_cv_c_intmax_t=no)]) | ||
29 | if test $gt_cv_c_intmax_t = yes; then | ||
30 | AC_DEFINE(HAVE_INTMAX_T, 1, | ||
31 | [Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>.]) | ||
32 | fi | ||
33 | ]) | ||
diff --git a/gl/m4/intmax_t.m4 b/gl/m4/intmax_t.m4 new file mode 100644 index 00000000..17c7b0ae --- /dev/null +++ b/gl/m4/intmax_t.m4 | |||
@@ -0,0 +1,61 @@ | |||
1 | # intmax_t.m4 serial 5 | ||
2 | dnl Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Paul Eggert. | ||
8 | |||
9 | AC_PREREQ(2.13) | ||
10 | |||
11 | # Define intmax_t to 'long' or 'long long' | ||
12 | # if it is not already defined in <stdint.h> or <inttypes.h>. | ||
13 | |||
14 | AC_DEFUN([gl_AC_TYPE_INTMAX_T], | ||
15 | [ | ||
16 | dnl For simplicity, we assume that a header file defines 'intmax_t' if and | ||
17 | dnl only if it defines 'uintmax_t'. | ||
18 | AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) | ||
19 | AC_REQUIRE([gl_AC_HEADER_STDINT_H]) | ||
20 | if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then | ||
21 | AC_REQUIRE([gl_AC_TYPE_LONG_LONG]) | ||
22 | test $ac_cv_type_long_long = yes \ | ||
23 | && ac_type='long long' \ | ||
24 | || ac_type='long' | ||
25 | AC_DEFINE_UNQUOTED(intmax_t, $ac_type, | ||
26 | [Define to long or long long if <inttypes.h> and <stdint.h> don't define.]) | ||
27 | else | ||
28 | AC_DEFINE(HAVE_INTMAX_T, 1, | ||
29 | [Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>.]) | ||
30 | fi | ||
31 | ]) | ||
32 | |||
33 | dnl An alternative would be to explicitly test for 'intmax_t'. | ||
34 | |||
35 | AC_DEFUN([gt_AC_TYPE_INTMAX_T], | ||
36 | [ | ||
37 | AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) | ||
38 | AC_REQUIRE([gl_AC_HEADER_STDINT_H]) | ||
39 | AC_CACHE_CHECK(for intmax_t, gt_cv_c_intmax_t, | ||
40 | [AC_TRY_COMPILE([ | ||
41 | #include <stddef.h> | ||
42 | #include <stdlib.h> | ||
43 | #if HAVE_STDINT_H_WITH_UINTMAX | ||
44 | #include <stdint.h> | ||
45 | #endif | ||
46 | #if HAVE_INTTYPES_H_WITH_UINTMAX | ||
47 | #include <inttypes.h> | ||
48 | #endif | ||
49 | ], [intmax_t x = -1; return !x;], gt_cv_c_intmax_t=yes, gt_cv_c_intmax_t=no)]) | ||
50 | if test $gt_cv_c_intmax_t = yes; then | ||
51 | AC_DEFINE(HAVE_INTMAX_T, 1, | ||
52 | [Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>.]) | ||
53 | else | ||
54 | AC_REQUIRE([gl_AC_TYPE_LONG_LONG]) | ||
55 | test $ac_cv_type_long_long = yes \ | ||
56 | && ac_type='long long' \ | ||
57 | || ac_type='long' | ||
58 | AC_DEFINE_UNQUOTED(intmax_t, $ac_type, | ||
59 | [Define to long or long long if <stdint.h> and <inttypes.h> don't define.]) | ||
60 | fi | ||
61 | ]) | ||
diff --git a/gl/m4/inttypes-pri.m4 b/gl/m4/inttypes-pri.m4 new file mode 100644 index 00000000..7c7f8940 --- /dev/null +++ b/gl/m4/inttypes-pri.m4 | |||
@@ -0,0 +1,36 @@ | |||
1 | # inttypes-pri.m4 serial 4 (gettext-0.16) | ||
2 | dnl Copyright (C) 1997-2002, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | |||
9 | AC_PREREQ(2.52) | ||
10 | |||
11 | # Define PRI_MACROS_BROKEN if <inttypes.h> exists and defines the PRI* | ||
12 | # macros to non-string values. This is the case on AIX 4.3.3. | ||
13 | |||
14 | AC_DEFUN([gt_INTTYPES_PRI], | ||
15 | [ | ||
16 | AC_CHECK_HEADERS([inttypes.h]) | ||
17 | if test $ac_cv_header_inttypes_h = yes; then | ||
18 | AC_CACHE_CHECK([whether the inttypes.h PRIxNN macros are broken], | ||
19 | gt_cv_inttypes_pri_broken, | ||
20 | [ | ||
21 | AC_TRY_COMPILE([#include <inttypes.h> | ||
22 | #ifdef PRId32 | ||
23 | char *p = PRId32; | ||
24 | #endif | ||
25 | ], [], gt_cv_inttypes_pri_broken=no, gt_cv_inttypes_pri_broken=yes) | ||
26 | ]) | ||
27 | fi | ||
28 | if test "$gt_cv_inttypes_pri_broken" = yes; then | ||
29 | AC_DEFINE_UNQUOTED(PRI_MACROS_BROKEN, 1, | ||
30 | [Define if <inttypes.h> exists and defines unusable PRI* macros.]) | ||
31 | PRI_MACROS_BROKEN=1 | ||
32 | else | ||
33 | PRI_MACROS_BROKEN=0 | ||
34 | fi | ||
35 | AC_SUBST([PRI_MACROS_BROKEN]) | ||
36 | ]) | ||
diff --git a/gl/m4/inttypes_h.m4 b/gl/m4/inttypes_h.m4 new file mode 100644 index 00000000..edc8ecb2 --- /dev/null +++ b/gl/m4/inttypes_h.m4 | |||
@@ -0,0 +1,26 @@ | |||
1 | # inttypes_h.m4 serial 7 | ||
2 | dnl Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Paul Eggert. | ||
8 | |||
9 | # Define HAVE_INTTYPES_H_WITH_UINTMAX if <inttypes.h> exists, | ||
10 | # doesn't clash with <sys/types.h>, and declares uintmax_t. | ||
11 | |||
12 | AC_DEFUN([gl_AC_HEADER_INTTYPES_H], | ||
13 | [ | ||
14 | AC_CACHE_CHECK([for inttypes.h], gl_cv_header_inttypes_h, | ||
15 | [AC_TRY_COMPILE( | ||
16 | [#include <sys/types.h> | ||
17 | #include <inttypes.h>], | ||
18 | [uintmax_t i = (uintmax_t) -1; return !i;], | ||
19 | gl_cv_header_inttypes_h=yes, | ||
20 | gl_cv_header_inttypes_h=no)]) | ||
21 | if test $gl_cv_header_inttypes_h = yes; then | ||
22 | AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H_WITH_UINTMAX, 1, | ||
23 | [Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, | ||
24 | and declares uintmax_t. ]) | ||
25 | fi | ||
26 | ]) | ||
diff --git a/gl/m4/lcmessage.m4 b/gl/m4/lcmessage.m4 new file mode 100644 index 00000000..19aa77e4 --- /dev/null +++ b/gl/m4/lcmessage.m4 | |||
@@ -0,0 +1,30 @@ | |||
1 | # lcmessage.m4 serial 4 (gettext-0.14.2) | ||
2 | dnl Copyright (C) 1995-2002, 2004-2005 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | dnl | ||
7 | dnl This file can can be used in projects which are not available under | ||
8 | dnl the GNU General Public License or the GNU Library General Public | ||
9 | dnl License but which still want to provide support for the GNU gettext | ||
10 | dnl functionality. | ||
11 | dnl Please note that the actual code of the GNU gettext library is covered | ||
12 | dnl by the GNU Library General Public License, and the rest of the GNU | ||
13 | dnl gettext package package is covered by the GNU General Public License. | ||
14 | dnl They are *not* in the public domain. | ||
15 | |||
16 | dnl Authors: | ||
17 | dnl Ulrich Drepper <drepper@cygnus.com>, 1995. | ||
18 | |||
19 | # Check whether LC_MESSAGES is available in <locale.h>. | ||
20 | |||
21 | AC_DEFUN([gt_LC_MESSAGES], | ||
22 | [ | ||
23 | AC_CACHE_CHECK([for LC_MESSAGES], gt_cv_val_LC_MESSAGES, | ||
24 | [AC_TRY_LINK([#include <locale.h>], [return LC_MESSAGES], | ||
25 | gt_cv_val_LC_MESSAGES=yes, gt_cv_val_LC_MESSAGES=no)]) | ||
26 | if test $gt_cv_val_LC_MESSAGES = yes; then | ||
27 | AC_DEFINE(HAVE_LC_MESSAGES, 1, | ||
28 | [Define if your <locale.h> file defines LC_MESSAGES.]) | ||
29 | fi | ||
30 | ]) | ||
diff --git a/gl/m4/lib-ld.m4 b/gl/m4/lib-ld.m4 new file mode 100644 index 00000000..96c4e2c3 --- /dev/null +++ b/gl/m4/lib-ld.m4 | |||
@@ -0,0 +1,110 @@ | |||
1 | # lib-ld.m4 serial 3 (gettext-0.13) | ||
2 | dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl Subroutines of libtool.m4, | ||
8 | dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision | ||
9 | dnl with libtool.m4. | ||
10 | |||
11 | dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. | ||
12 | AC_DEFUN([AC_LIB_PROG_LD_GNU], | ||
13 | [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, | ||
14 | [# I'd rather use --version here, but apparently some GNU ld's only accept -v. | ||
15 | case `$LD -v 2>&1 </dev/null` in | ||
16 | *GNU* | *'with BFD'*) | ||
17 | acl_cv_prog_gnu_ld=yes ;; | ||
18 | *) | ||
19 | acl_cv_prog_gnu_ld=no ;; | ||
20 | esac]) | ||
21 | with_gnu_ld=$acl_cv_prog_gnu_ld | ||
22 | ]) | ||
23 | |||
24 | dnl From libtool-1.4. Sets the variable LD. | ||
25 | AC_DEFUN([AC_LIB_PROG_LD], | ||
26 | [AC_ARG_WITH(gnu-ld, | ||
27 | [ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], | ||
28 | test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) | ||
29 | AC_REQUIRE([AC_PROG_CC])dnl | ||
30 | AC_REQUIRE([AC_CANONICAL_HOST])dnl | ||
31 | # Prepare PATH_SEPARATOR. | ||
32 | # The user is always right. | ||
33 | if test "${PATH_SEPARATOR+set}" != set; then | ||
34 | echo "#! /bin/sh" >conf$$.sh | ||
35 | echo "exit 0" >>conf$$.sh | ||
36 | chmod +x conf$$.sh | ||
37 | if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then | ||
38 | PATH_SEPARATOR=';' | ||
39 | else | ||
40 | PATH_SEPARATOR=: | ||
41 | fi | ||
42 | rm -f conf$$.sh | ||
43 | fi | ||
44 | ac_prog=ld | ||
45 | if test "$GCC" = yes; then | ||
46 | # Check if gcc -print-prog-name=ld gives a path. | ||
47 | AC_MSG_CHECKING([for ld used by GCC]) | ||
48 | case $host in | ||
49 | *-*-mingw*) | ||
50 | # gcc leaves a trailing carriage return which upsets mingw | ||
51 | ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; | ||
52 | *) | ||
53 | ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; | ||
54 | esac | ||
55 | case $ac_prog in | ||
56 | # Accept absolute paths. | ||
57 | [[\\/]* | [A-Za-z]:[\\/]*)] | ||
58 | [re_direlt='/[^/][^/]*/\.\./'] | ||
59 | # Canonicalize the path of ld | ||
60 | ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` | ||
61 | while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do | ||
62 | ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` | ||
63 | done | ||
64 | test -z "$LD" && LD="$ac_prog" | ||
65 | ;; | ||
66 | "") | ||
67 | # If it fails, then pretend we aren't using GCC. | ||
68 | ac_prog=ld | ||
69 | ;; | ||
70 | *) | ||
71 | # If it is relative, then search for the first ld in PATH. | ||
72 | with_gnu_ld=unknown | ||
73 | ;; | ||
74 | esac | ||
75 | elif test "$with_gnu_ld" = yes; then | ||
76 | AC_MSG_CHECKING([for GNU ld]) | ||
77 | else | ||
78 | AC_MSG_CHECKING([for non-GNU ld]) | ||
79 | fi | ||
80 | AC_CACHE_VAL(acl_cv_path_LD, | ||
81 | [if test -z "$LD"; then | ||
82 | IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" | ||
83 | for ac_dir in $PATH; do | ||
84 | test -z "$ac_dir" && ac_dir=. | ||
85 | if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then | ||
86 | acl_cv_path_LD="$ac_dir/$ac_prog" | ||
87 | # Check to see if the program is GNU ld. I'd rather use --version, | ||
88 | # but apparently some GNU ld's only accept -v. | ||
89 | # Break only if it was the GNU/non-GNU ld that we prefer. | ||
90 | case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in | ||
91 | *GNU* | *'with BFD'*) | ||
92 | test "$with_gnu_ld" != no && break ;; | ||
93 | *) | ||
94 | test "$with_gnu_ld" != yes && break ;; | ||
95 | esac | ||
96 | fi | ||
97 | done | ||
98 | IFS="$ac_save_ifs" | ||
99 | else | ||
100 | acl_cv_path_LD="$LD" # Let the user override the test with a path. | ||
101 | fi]) | ||
102 | LD="$acl_cv_path_LD" | ||
103 | if test -n "$LD"; then | ||
104 | AC_MSG_RESULT($LD) | ||
105 | else | ||
106 | AC_MSG_RESULT(no) | ||
107 | fi | ||
108 | test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) | ||
109 | AC_LIB_PROG_LD_GNU | ||
110 | ]) | ||
diff --git a/gl/m4/lib-link.m4 b/gl/m4/lib-link.m4 new file mode 100644 index 00000000..f157d983 --- /dev/null +++ b/gl/m4/lib-link.m4 | |||
@@ -0,0 +1,709 @@ | |||
1 | # lib-link.m4 serial 13 (gettext-0.16.2) | ||
2 | dnl Copyright (C) 2001-2007 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | |||
9 | AC_PREREQ(2.54) | ||
10 | |||
11 | dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and | ||
12 | dnl the libraries corresponding to explicit and implicit dependencies. | ||
13 | dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and | ||
14 | dnl augments the CPPFLAGS variable. | ||
15 | dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname | ||
16 | dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. | ||
17 | AC_DEFUN([AC_LIB_LINKFLAGS], | ||
18 | [ | ||
19 | AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) | ||
20 | AC_REQUIRE([AC_LIB_RPATH]) | ||
21 | define([Name],[translit([$1],[./-], [___])]) | ||
22 | define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], | ||
23 | [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) | ||
24 | AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ | ||
25 | AC_LIB_LINKFLAGS_BODY([$1], [$2]) | ||
26 | ac_cv_lib[]Name[]_libs="$LIB[]NAME" | ||
27 | ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" | ||
28 | ac_cv_lib[]Name[]_cppflags="$INC[]NAME" | ||
29 | ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX" | ||
30 | ]) | ||
31 | LIB[]NAME="$ac_cv_lib[]Name[]_libs" | ||
32 | LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" | ||
33 | INC[]NAME="$ac_cv_lib[]Name[]_cppflags" | ||
34 | LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix" | ||
35 | AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) | ||
36 | AC_SUBST([LIB]NAME) | ||
37 | AC_SUBST([LTLIB]NAME) | ||
38 | AC_SUBST([LIB]NAME[_PREFIX]) | ||
39 | dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the | ||
40 | dnl results of this search when this library appears as a dependency. | ||
41 | HAVE_LIB[]NAME=yes | ||
42 | undefine([Name]) | ||
43 | undefine([NAME]) | ||
44 | ]) | ||
45 | |||
46 | dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) | ||
47 | dnl searches for libname and the libraries corresponding to explicit and | ||
48 | dnl implicit dependencies, together with the specified include files and | ||
49 | dnl the ability to compile and link the specified testcode. If found, it | ||
50 | dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and | ||
51 | dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and | ||
52 | dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs | ||
53 | dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. | ||
54 | dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname | ||
55 | dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem. | ||
56 | AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], | ||
57 | [ | ||
58 | AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) | ||
59 | AC_REQUIRE([AC_LIB_RPATH]) | ||
60 | define([Name],[translit([$1],[./-], [___])]) | ||
61 | define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], | ||
62 | [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) | ||
63 | |||
64 | dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME | ||
65 | dnl accordingly. | ||
66 | AC_LIB_LINKFLAGS_BODY([$1], [$2]) | ||
67 | |||
68 | dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, | ||
69 | dnl because if the user has installed lib[]Name and not disabled its use | ||
70 | dnl via --without-lib[]Name-prefix, he wants to use it. | ||
71 | ac_save_CPPFLAGS="$CPPFLAGS" | ||
72 | AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) | ||
73 | |||
74 | AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ | ||
75 | ac_save_LIBS="$LIBS" | ||
76 | LIBS="$LIBS $LIB[]NAME" | ||
77 | AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) | ||
78 | LIBS="$ac_save_LIBS" | ||
79 | ]) | ||
80 | if test "$ac_cv_lib[]Name" = yes; then | ||
81 | HAVE_LIB[]NAME=yes | ||
82 | AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) | ||
83 | AC_MSG_CHECKING([how to link with lib[]$1]) | ||
84 | AC_MSG_RESULT([$LIB[]NAME]) | ||
85 | else | ||
86 | HAVE_LIB[]NAME=no | ||
87 | dnl If $LIB[]NAME didn't lead to a usable library, we don't need | ||
88 | dnl $INC[]NAME either. | ||
89 | CPPFLAGS="$ac_save_CPPFLAGS" | ||
90 | LIB[]NAME= | ||
91 | LTLIB[]NAME= | ||
92 | LIB[]NAME[]_PREFIX= | ||
93 | fi | ||
94 | AC_SUBST([HAVE_LIB]NAME) | ||
95 | AC_SUBST([LIB]NAME) | ||
96 | AC_SUBST([LTLIB]NAME) | ||
97 | AC_SUBST([LIB]NAME[_PREFIX]) | ||
98 | undefine([Name]) | ||
99 | undefine([NAME]) | ||
100 | ]) | ||
101 | |||
102 | dnl Determine the platform dependent parameters needed to use rpath: | ||
103 | dnl acl_libext, | ||
104 | dnl acl_shlibext, | ||
105 | dnl acl_hardcode_libdir_flag_spec, | ||
106 | dnl acl_hardcode_libdir_separator, | ||
107 | dnl acl_hardcode_direct, | ||
108 | dnl acl_hardcode_minus_L. | ||
109 | AC_DEFUN([AC_LIB_RPATH], | ||
110 | [ | ||
111 | dnl Tell automake >= 1.10 to complain if config.rpath is missing. | ||
112 | m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) | ||
113 | AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS | ||
114 | AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld | ||
115 | AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host | ||
116 | AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir | ||
117 | AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ | ||
118 | CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ | ||
119 | ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh | ||
120 | . ./conftest.sh | ||
121 | rm -f ./conftest.sh | ||
122 | acl_cv_rpath=done | ||
123 | ]) | ||
124 | wl="$acl_cv_wl" | ||
125 | acl_libext="$acl_cv_libext" | ||
126 | acl_shlibext="$acl_cv_shlibext" | ||
127 | acl_libname_spec="$acl_cv_libname_spec" | ||
128 | acl_library_names_spec="$acl_cv_library_names_spec" | ||
129 | acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" | ||
130 | acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" | ||
131 | acl_hardcode_direct="$acl_cv_hardcode_direct" | ||
132 | acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" | ||
133 | dnl Determine whether the user wants rpath handling at all. | ||
134 | AC_ARG_ENABLE(rpath, | ||
135 | [ --disable-rpath do not hardcode runtime library paths], | ||
136 | :, enable_rpath=yes) | ||
137 | ]) | ||
138 | |||
139 | dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and | ||
140 | dnl the libraries corresponding to explicit and implicit dependencies. | ||
141 | dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. | ||
142 | dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found | ||
143 | dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. | ||
144 | AC_DEFUN([AC_LIB_LINKFLAGS_BODY], | ||
145 | [ | ||
146 | AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) | ||
147 | define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], | ||
148 | [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) | ||
149 | dnl Autoconf >= 2.61 supports dots in --with options. | ||
150 | define([N_A_M_E],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit([$1],[.],[_])],[$1])]) | ||
151 | dnl By default, look in $includedir and $libdir. | ||
152 | use_additional=yes | ||
153 | AC_LIB_WITH_FINAL_PREFIX([ | ||
154 | eval additional_includedir=\"$includedir\" | ||
155 | eval additional_libdir=\"$libdir\" | ||
156 | ]) | ||
157 | AC_LIB_ARG_WITH([lib]N_A_M_E[-prefix], | ||
158 | [ --with-lib]N_A_M_E[-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib | ||
159 | --without-lib]N_A_M_E[-prefix don't search for lib$1 in includedir and libdir], | ||
160 | [ | ||
161 | if test "X$withval" = "Xno"; then | ||
162 | use_additional=no | ||
163 | else | ||
164 | if test "X$withval" = "X"; then | ||
165 | AC_LIB_WITH_FINAL_PREFIX([ | ||
166 | eval additional_includedir=\"$includedir\" | ||
167 | eval additional_libdir=\"$libdir\" | ||
168 | ]) | ||
169 | else | ||
170 | additional_includedir="$withval/include" | ||
171 | additional_libdir="$withval/$acl_libdirstem" | ||
172 | fi | ||
173 | fi | ||
174 | ]) | ||
175 | dnl Search the library and its dependencies in $additional_libdir and | ||
176 | dnl $LDFLAGS. Using breadth-first-seach. | ||
177 | LIB[]NAME= | ||
178 | LTLIB[]NAME= | ||
179 | INC[]NAME= | ||
180 | LIB[]NAME[]_PREFIX= | ||
181 | rpathdirs= | ||
182 | ltrpathdirs= | ||
183 | names_already_handled= | ||
184 | names_next_round='$1 $2' | ||
185 | while test -n "$names_next_round"; do | ||
186 | names_this_round="$names_next_round" | ||
187 | names_next_round= | ||
188 | for name in $names_this_round; do | ||
189 | already_handled= | ||
190 | for n in $names_already_handled; do | ||
191 | if test "$n" = "$name"; then | ||
192 | already_handled=yes | ||
193 | break | ||
194 | fi | ||
195 | done | ||
196 | if test -z "$already_handled"; then | ||
197 | names_already_handled="$names_already_handled $name" | ||
198 | dnl See if it was already located by an earlier AC_LIB_LINKFLAGS | ||
199 | dnl or AC_LIB_HAVE_LINKFLAGS call. | ||
200 | uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` | ||
201 | eval value=\"\$HAVE_LIB$uppername\" | ||
202 | if test -n "$value"; then | ||
203 | if test "$value" = yes; then | ||
204 | eval value=\"\$LIB$uppername\" | ||
205 | test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" | ||
206 | eval value=\"\$LTLIB$uppername\" | ||
207 | test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" | ||
208 | else | ||
209 | dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined | ||
210 | dnl that this library doesn't exist. So just drop it. | ||
211 | : | ||
212 | fi | ||
213 | else | ||
214 | dnl Search the library lib$name in $additional_libdir and $LDFLAGS | ||
215 | dnl and the already constructed $LIBNAME/$LTLIBNAME. | ||
216 | found_dir= | ||
217 | found_la= | ||
218 | found_so= | ||
219 | found_a= | ||
220 | eval libname=\"$acl_libname_spec\" # typically: libname=lib$name | ||
221 | if test -n "$acl_shlibext"; then | ||
222 | shrext=".$acl_shlibext" # typically: shrext=.so | ||
223 | else | ||
224 | shrext= | ||
225 | fi | ||
226 | if test $use_additional = yes; then | ||
227 | dir="$additional_libdir" | ||
228 | dnl The same code as in the loop below: | ||
229 | dnl First look for a shared library. | ||
230 | if test -n "$acl_shlibext"; then | ||
231 | if test -f "$dir/$libname$shrext"; then | ||
232 | found_dir="$dir" | ||
233 | found_so="$dir/$libname$shrext" | ||
234 | else | ||
235 | if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then | ||
236 | ver=`(cd "$dir" && \ | ||
237 | for f in "$libname$shrext".*; do echo "$f"; done \ | ||
238 | | sed -e "s,^$libname$shrext\\\\.,," \ | ||
239 | | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | ||
240 | | sed 1q ) 2>/dev/null` | ||
241 | if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then | ||
242 | found_dir="$dir" | ||
243 | found_so="$dir/$libname$shrext.$ver" | ||
244 | fi | ||
245 | else | ||
246 | eval library_names=\"$acl_library_names_spec\" | ||
247 | for f in $library_names; do | ||
248 | if test -f "$dir/$f"; then | ||
249 | found_dir="$dir" | ||
250 | found_so="$dir/$f" | ||
251 | break | ||
252 | fi | ||
253 | done | ||
254 | fi | ||
255 | fi | ||
256 | fi | ||
257 | dnl Then look for a static library. | ||
258 | if test "X$found_dir" = "X"; then | ||
259 | if test -f "$dir/$libname.$acl_libext"; then | ||
260 | found_dir="$dir" | ||
261 | found_a="$dir/$libname.$acl_libext" | ||
262 | fi | ||
263 | fi | ||
264 | if test "X$found_dir" != "X"; then | ||
265 | if test -f "$dir/$libname.la"; then | ||
266 | found_la="$dir/$libname.la" | ||
267 | fi | ||
268 | fi | ||
269 | fi | ||
270 | if test "X$found_dir" = "X"; then | ||
271 | for x in $LDFLAGS $LTLIB[]NAME; do | ||
272 | AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | ||
273 | case "$x" in | ||
274 | -L*) | ||
275 | dir=`echo "X$x" | sed -e 's/^X-L//'` | ||
276 | dnl First look for a shared library. | ||
277 | if test -n "$acl_shlibext"; then | ||
278 | if test -f "$dir/$libname$shrext"; then | ||
279 | found_dir="$dir" | ||
280 | found_so="$dir/$libname$shrext" | ||
281 | else | ||
282 | if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then | ||
283 | ver=`(cd "$dir" && \ | ||
284 | for f in "$libname$shrext".*; do echo "$f"; done \ | ||
285 | | sed -e "s,^$libname$shrext\\\\.,," \ | ||
286 | | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | ||
287 | | sed 1q ) 2>/dev/null` | ||
288 | if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then | ||
289 | found_dir="$dir" | ||
290 | found_so="$dir/$libname$shrext.$ver" | ||
291 | fi | ||
292 | else | ||
293 | eval library_names=\"$acl_library_names_spec\" | ||
294 | for f in $library_names; do | ||
295 | if test -f "$dir/$f"; then | ||
296 | found_dir="$dir" | ||
297 | found_so="$dir/$f" | ||
298 | break | ||
299 | fi | ||
300 | done | ||
301 | fi | ||
302 | fi | ||
303 | fi | ||
304 | dnl Then look for a static library. | ||
305 | if test "X$found_dir" = "X"; then | ||
306 | if test -f "$dir/$libname.$acl_libext"; then | ||
307 | found_dir="$dir" | ||
308 | found_a="$dir/$libname.$acl_libext" | ||
309 | fi | ||
310 | fi | ||
311 | if test "X$found_dir" != "X"; then | ||
312 | if test -f "$dir/$libname.la"; then | ||
313 | found_la="$dir/$libname.la" | ||
314 | fi | ||
315 | fi | ||
316 | ;; | ||
317 | esac | ||
318 | if test "X$found_dir" != "X"; then | ||
319 | break | ||
320 | fi | ||
321 | done | ||
322 | fi | ||
323 | if test "X$found_dir" != "X"; then | ||
324 | dnl Found the library. | ||
325 | LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" | ||
326 | if test "X$found_so" != "X"; then | ||
327 | dnl Linking with a shared library. We attempt to hardcode its | ||
328 | dnl directory into the executable's runpath, unless it's the | ||
329 | dnl standard /usr/lib. | ||
330 | if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then | ||
331 | dnl No hardcoding is needed. | ||
332 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" | ||
333 | else | ||
334 | dnl Use an explicit option to hardcode DIR into the resulting | ||
335 | dnl binary. | ||
336 | dnl Potentially add DIR to ltrpathdirs. | ||
337 | dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. | ||
338 | haveit= | ||
339 | for x in $ltrpathdirs; do | ||
340 | if test "X$x" = "X$found_dir"; then | ||
341 | haveit=yes | ||
342 | break | ||
343 | fi | ||
344 | done | ||
345 | if test -z "$haveit"; then | ||
346 | ltrpathdirs="$ltrpathdirs $found_dir" | ||
347 | fi | ||
348 | dnl The hardcoding into $LIBNAME is system dependent. | ||
349 | if test "$acl_hardcode_direct" = yes; then | ||
350 | dnl Using DIR/libNAME.so during linking hardcodes DIR into the | ||
351 | dnl resulting binary. | ||
352 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" | ||
353 | else | ||
354 | if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then | ||
355 | dnl Use an explicit option to hardcode DIR into the resulting | ||
356 | dnl binary. | ||
357 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" | ||
358 | dnl Potentially add DIR to rpathdirs. | ||
359 | dnl The rpathdirs will be appended to $LIBNAME at the end. | ||
360 | haveit= | ||
361 | for x in $rpathdirs; do | ||
362 | if test "X$x" = "X$found_dir"; then | ||
363 | haveit=yes | ||
364 | break | ||
365 | fi | ||
366 | done | ||
367 | if test -z "$haveit"; then | ||
368 | rpathdirs="$rpathdirs $found_dir" | ||
369 | fi | ||
370 | else | ||
371 | dnl Rely on "-L$found_dir". | ||
372 | dnl But don't add it if it's already contained in the LDFLAGS | ||
373 | dnl or the already constructed $LIBNAME | ||
374 | haveit= | ||
375 | for x in $LDFLAGS $LIB[]NAME; do | ||
376 | AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | ||
377 | if test "X$x" = "X-L$found_dir"; then | ||
378 | haveit=yes | ||
379 | break | ||
380 | fi | ||
381 | done | ||
382 | if test -z "$haveit"; then | ||
383 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" | ||
384 | fi | ||
385 | if test "$acl_hardcode_minus_L" != no; then | ||
386 | dnl FIXME: Not sure whether we should use | ||
387 | dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" | ||
388 | dnl here. | ||
389 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" | ||
390 | else | ||
391 | dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH | ||
392 | dnl here, because this doesn't fit in flags passed to the | ||
393 | dnl compiler. So give up. No hardcoding. This affects only | ||
394 | dnl very old systems. | ||
395 | dnl FIXME: Not sure whether we should use | ||
396 | dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" | ||
397 | dnl here. | ||
398 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" | ||
399 | fi | ||
400 | fi | ||
401 | fi | ||
402 | fi | ||
403 | else | ||
404 | if test "X$found_a" != "X"; then | ||
405 | dnl Linking with a static library. | ||
406 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" | ||
407 | else | ||
408 | dnl We shouldn't come here, but anyway it's good to have a | ||
409 | dnl fallback. | ||
410 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" | ||
411 | fi | ||
412 | fi | ||
413 | dnl Assume the include files are nearby. | ||
414 | additional_includedir= | ||
415 | case "$found_dir" in | ||
416 | */$acl_libdirstem | */$acl_libdirstem/) | ||
417 | basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` | ||
418 | LIB[]NAME[]_PREFIX="$basedir" | ||
419 | additional_includedir="$basedir/include" | ||
420 | ;; | ||
421 | esac | ||
422 | if test "X$additional_includedir" != "X"; then | ||
423 | dnl Potentially add $additional_includedir to $INCNAME. | ||
424 | dnl But don't add it | ||
425 | dnl 1. if it's the standard /usr/include, | ||
426 | dnl 2. if it's /usr/local/include and we are using GCC on Linux, | ||
427 | dnl 3. if it's already present in $CPPFLAGS or the already | ||
428 | dnl constructed $INCNAME, | ||
429 | dnl 4. if it doesn't exist as a directory. | ||
430 | if test "X$additional_includedir" != "X/usr/include"; then | ||
431 | haveit= | ||
432 | if test "X$additional_includedir" = "X/usr/local/include"; then | ||
433 | if test -n "$GCC"; then | ||
434 | case $host_os in | ||
435 | linux* | gnu* | k*bsd*-gnu) haveit=yes;; | ||
436 | esac | ||
437 | fi | ||
438 | fi | ||
439 | if test -z "$haveit"; then | ||
440 | for x in $CPPFLAGS $INC[]NAME; do | ||
441 | AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | ||
442 | if test "X$x" = "X-I$additional_includedir"; then | ||
443 | haveit=yes | ||
444 | break | ||
445 | fi | ||
446 | done | ||
447 | if test -z "$haveit"; then | ||
448 | if test -d "$additional_includedir"; then | ||
449 | dnl Really add $additional_includedir to $INCNAME. | ||
450 | INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" | ||
451 | fi | ||
452 | fi | ||
453 | fi | ||
454 | fi | ||
455 | fi | ||
456 | dnl Look for dependencies. | ||
457 | if test -n "$found_la"; then | ||
458 | dnl Read the .la file. It defines the variables | ||
459 | dnl dlname, library_names, old_library, dependency_libs, current, | ||
460 | dnl age, revision, installed, dlopen, dlpreopen, libdir. | ||
461 | save_libdir="$libdir" | ||
462 | case "$found_la" in | ||
463 | */* | *\\*) . "$found_la" ;; | ||
464 | *) . "./$found_la" ;; | ||
465 | esac | ||
466 | libdir="$save_libdir" | ||
467 | dnl We use only dependency_libs. | ||
468 | for dep in $dependency_libs; do | ||
469 | case "$dep" in | ||
470 | -L*) | ||
471 | additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` | ||
472 | dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. | ||
473 | dnl But don't add it | ||
474 | dnl 1. if it's the standard /usr/lib, | ||
475 | dnl 2. if it's /usr/local/lib and we are using GCC on Linux, | ||
476 | dnl 3. if it's already present in $LDFLAGS or the already | ||
477 | dnl constructed $LIBNAME, | ||
478 | dnl 4. if it doesn't exist as a directory. | ||
479 | if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then | ||
480 | haveit= | ||
481 | if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then | ||
482 | if test -n "$GCC"; then | ||
483 | case $host_os in | ||
484 | linux* | gnu* | k*bsd*-gnu) haveit=yes;; | ||
485 | esac | ||
486 | fi | ||
487 | fi | ||
488 | if test -z "$haveit"; then | ||
489 | haveit= | ||
490 | for x in $LDFLAGS $LIB[]NAME; do | ||
491 | AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | ||
492 | if test "X$x" = "X-L$additional_libdir"; then | ||
493 | haveit=yes | ||
494 | break | ||
495 | fi | ||
496 | done | ||
497 | if test -z "$haveit"; then | ||
498 | if test -d "$additional_libdir"; then | ||
499 | dnl Really add $additional_libdir to $LIBNAME. | ||
500 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" | ||
501 | fi | ||
502 | fi | ||
503 | haveit= | ||
504 | for x in $LDFLAGS $LTLIB[]NAME; do | ||
505 | AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | ||
506 | if test "X$x" = "X-L$additional_libdir"; then | ||
507 | haveit=yes | ||
508 | break | ||
509 | fi | ||
510 | done | ||
511 | if test -z "$haveit"; then | ||
512 | if test -d "$additional_libdir"; then | ||
513 | dnl Really add $additional_libdir to $LTLIBNAME. | ||
514 | LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" | ||
515 | fi | ||
516 | fi | ||
517 | fi | ||
518 | fi | ||
519 | ;; | ||
520 | -R*) | ||
521 | dir=`echo "X$dep" | sed -e 's/^X-R//'` | ||
522 | if test "$enable_rpath" != no; then | ||
523 | dnl Potentially add DIR to rpathdirs. | ||
524 | dnl The rpathdirs will be appended to $LIBNAME at the end. | ||
525 | haveit= | ||
526 | for x in $rpathdirs; do | ||
527 | if test "X$x" = "X$dir"; then | ||
528 | haveit=yes | ||
529 | break | ||
530 | fi | ||
531 | done | ||
532 | if test -z "$haveit"; then | ||
533 | rpathdirs="$rpathdirs $dir" | ||
534 | fi | ||
535 | dnl Potentially add DIR to ltrpathdirs. | ||
536 | dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. | ||
537 | haveit= | ||
538 | for x in $ltrpathdirs; do | ||
539 | if test "X$x" = "X$dir"; then | ||
540 | haveit=yes | ||
541 | break | ||
542 | fi | ||
543 | done | ||
544 | if test -z "$haveit"; then | ||
545 | ltrpathdirs="$ltrpathdirs $dir" | ||
546 | fi | ||
547 | fi | ||
548 | ;; | ||
549 | -l*) | ||
550 | dnl Handle this in the next round. | ||
551 | names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` | ||
552 | ;; | ||
553 | *.la) | ||
554 | dnl Handle this in the next round. Throw away the .la's | ||
555 | dnl directory; it is already contained in a preceding -L | ||
556 | dnl option. | ||
557 | names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` | ||
558 | ;; | ||
559 | *) | ||
560 | dnl Most likely an immediate library name. | ||
561 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" | ||
562 | LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" | ||
563 | ;; | ||
564 | esac | ||
565 | done | ||
566 | fi | ||
567 | else | ||
568 | dnl Didn't find the library; assume it is in the system directories | ||
569 | dnl known to the linker and runtime loader. (All the system | ||
570 | dnl directories known to the linker should also be known to the | ||
571 | dnl runtime loader, otherwise the system is severely misconfigured.) | ||
572 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" | ||
573 | LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" | ||
574 | fi | ||
575 | fi | ||
576 | fi | ||
577 | done | ||
578 | done | ||
579 | if test "X$rpathdirs" != "X"; then | ||
580 | if test -n "$acl_hardcode_libdir_separator"; then | ||
581 | dnl Weird platform: only the last -rpath option counts, the user must | ||
582 | dnl pass all path elements in one option. We can arrange that for a | ||
583 | dnl single library, but not when more than one $LIBNAMEs are used. | ||
584 | alldirs= | ||
585 | for found_dir in $rpathdirs; do | ||
586 | alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" | ||
587 | done | ||
588 | dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. | ||
589 | acl_save_libdir="$libdir" | ||
590 | libdir="$alldirs" | ||
591 | eval flag=\"$acl_hardcode_libdir_flag_spec\" | ||
592 | libdir="$acl_save_libdir" | ||
593 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" | ||
594 | else | ||
595 | dnl The -rpath options are cumulative. | ||
596 | for found_dir in $rpathdirs; do | ||
597 | acl_save_libdir="$libdir" | ||
598 | libdir="$found_dir" | ||
599 | eval flag=\"$acl_hardcode_libdir_flag_spec\" | ||
600 | libdir="$acl_save_libdir" | ||
601 | LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" | ||
602 | done | ||
603 | fi | ||
604 | fi | ||
605 | if test "X$ltrpathdirs" != "X"; then | ||
606 | dnl When using libtool, the option that works for both libraries and | ||
607 | dnl executables is -R. The -R options are cumulative. | ||
608 | for found_dir in $ltrpathdirs; do | ||
609 | LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" | ||
610 | done | ||
611 | fi | ||
612 | ]) | ||
613 | |||
614 | dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, | ||
615 | dnl unless already present in VAR. | ||
616 | dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes | ||
617 | dnl contains two or three consecutive elements that belong together. | ||
618 | AC_DEFUN([AC_LIB_APPENDTOVAR], | ||
619 | [ | ||
620 | for element in [$2]; do | ||
621 | haveit= | ||
622 | for x in $[$1]; do | ||
623 | AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | ||
624 | if test "X$x" = "X$element"; then | ||
625 | haveit=yes | ||
626 | break | ||
627 | fi | ||
628 | done | ||
629 | if test -z "$haveit"; then | ||
630 | [$1]="${[$1]}${[$1]:+ }$element" | ||
631 | fi | ||
632 | done | ||
633 | ]) | ||
634 | |||
635 | dnl For those cases where a variable contains several -L and -l options | ||
636 | dnl referring to unknown libraries and directories, this macro determines the | ||
637 | dnl necessary additional linker options for the runtime path. | ||
638 | dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) | ||
639 | dnl sets LDADDVAR to linker options needed together with LIBSVALUE. | ||
640 | dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, | ||
641 | dnl otherwise linking without libtool is assumed. | ||
642 | AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], | ||
643 | [ | ||
644 | AC_REQUIRE([AC_LIB_RPATH]) | ||
645 | AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) | ||
646 | $1= | ||
647 | if test "$enable_rpath" != no; then | ||
648 | if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then | ||
649 | dnl Use an explicit option to hardcode directories into the resulting | ||
650 | dnl binary. | ||
651 | rpathdirs= | ||
652 | next= | ||
653 | for opt in $2; do | ||
654 | if test -n "$next"; then | ||
655 | dir="$next" | ||
656 | dnl No need to hardcode the standard /usr/lib. | ||
657 | if test "X$dir" != "X/usr/$acl_libdirstem"; then | ||
658 | rpathdirs="$rpathdirs $dir" | ||
659 | fi | ||
660 | next= | ||
661 | else | ||
662 | case $opt in | ||
663 | -L) next=yes ;; | ||
664 | -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` | ||
665 | dnl No need to hardcode the standard /usr/lib. | ||
666 | if test "X$dir" != "X/usr/$acl_libdirstem"; then | ||
667 | rpathdirs="$rpathdirs $dir" | ||
668 | fi | ||
669 | next= ;; | ||
670 | *) next= ;; | ||
671 | esac | ||
672 | fi | ||
673 | done | ||
674 | if test "X$rpathdirs" != "X"; then | ||
675 | if test -n ""$3""; then | ||
676 | dnl libtool is used for linking. Use -R options. | ||
677 | for dir in $rpathdirs; do | ||
678 | $1="${$1}${$1:+ }-R$dir" | ||
679 | done | ||
680 | else | ||
681 | dnl The linker is used for linking directly. | ||
682 | if test -n "$acl_hardcode_libdir_separator"; then | ||
683 | dnl Weird platform: only the last -rpath option counts, the user | ||
684 | dnl must pass all path elements in one option. | ||
685 | alldirs= | ||
686 | for dir in $rpathdirs; do | ||
687 | alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" | ||
688 | done | ||
689 | acl_save_libdir="$libdir" | ||
690 | libdir="$alldirs" | ||
691 | eval flag=\"$acl_hardcode_libdir_flag_spec\" | ||
692 | libdir="$acl_save_libdir" | ||
693 | $1="$flag" | ||
694 | else | ||
695 | dnl The -rpath options are cumulative. | ||
696 | for dir in $rpathdirs; do | ||
697 | acl_save_libdir="$libdir" | ||
698 | libdir="$dir" | ||
699 | eval flag=\"$acl_hardcode_libdir_flag_spec\" | ||
700 | libdir="$acl_save_libdir" | ||
701 | $1="${$1}${$1:+ }$flag" | ||
702 | done | ||
703 | fi | ||
704 | fi | ||
705 | fi | ||
706 | fi | ||
707 | fi | ||
708 | AC_SUBST([$1]) | ||
709 | ]) | ||
diff --git a/gl/m4/lib-prefix.m4 b/gl/m4/lib-prefix.m4 new file mode 100644 index 00000000..a8684e17 --- /dev/null +++ b/gl/m4/lib-prefix.m4 | |||
@@ -0,0 +1,185 @@ | |||
1 | # lib-prefix.m4 serial 5 (gettext-0.15) | ||
2 | dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | |||
9 | dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and | ||
10 | dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't | ||
11 | dnl require excessive bracketing. | ||
12 | ifdef([AC_HELP_STRING], | ||
13 | [AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], | ||
14 | [AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) | ||
15 | |||
16 | dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed | ||
17 | dnl to access previously installed libraries. The basic assumption is that | ||
18 | dnl a user will want packages to use other packages he previously installed | ||
19 | dnl with the same --prefix option. | ||
20 | dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate | ||
21 | dnl libraries, but is otherwise very convenient. | ||
22 | AC_DEFUN([AC_LIB_PREFIX], | ||
23 | [ | ||
24 | AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) | ||
25 | AC_REQUIRE([AC_PROG_CC]) | ||
26 | AC_REQUIRE([AC_CANONICAL_HOST]) | ||
27 | AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) | ||
28 | AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) | ||
29 | dnl By default, look in $includedir and $libdir. | ||
30 | use_additional=yes | ||
31 | AC_LIB_WITH_FINAL_PREFIX([ | ||
32 | eval additional_includedir=\"$includedir\" | ||
33 | eval additional_libdir=\"$libdir\" | ||
34 | ]) | ||
35 | AC_LIB_ARG_WITH([lib-prefix], | ||
36 | [ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib | ||
37 | --without-lib-prefix don't search for libraries in includedir and libdir], | ||
38 | [ | ||
39 | if test "X$withval" = "Xno"; then | ||
40 | use_additional=no | ||
41 | else | ||
42 | if test "X$withval" = "X"; then | ||
43 | AC_LIB_WITH_FINAL_PREFIX([ | ||
44 | eval additional_includedir=\"$includedir\" | ||
45 | eval additional_libdir=\"$libdir\" | ||
46 | ]) | ||
47 | else | ||
48 | additional_includedir="$withval/include" | ||
49 | additional_libdir="$withval/$acl_libdirstem" | ||
50 | fi | ||
51 | fi | ||
52 | ]) | ||
53 | if test $use_additional = yes; then | ||
54 | dnl Potentially add $additional_includedir to $CPPFLAGS. | ||
55 | dnl But don't add it | ||
56 | dnl 1. if it's the standard /usr/include, | ||
57 | dnl 2. if it's already present in $CPPFLAGS, | ||
58 | dnl 3. if it's /usr/local/include and we are using GCC on Linux, | ||
59 | dnl 4. if it doesn't exist as a directory. | ||
60 | if test "X$additional_includedir" != "X/usr/include"; then | ||
61 | haveit= | ||
62 | for x in $CPPFLAGS; do | ||
63 | AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | ||
64 | if test "X$x" = "X-I$additional_includedir"; then | ||
65 | haveit=yes | ||
66 | break | ||
67 | fi | ||
68 | done | ||
69 | if test -z "$haveit"; then | ||
70 | if test "X$additional_includedir" = "X/usr/local/include"; then | ||
71 | if test -n "$GCC"; then | ||
72 | case $host_os in | ||
73 | linux* | gnu* | k*bsd*-gnu) haveit=yes;; | ||
74 | esac | ||
75 | fi | ||
76 | fi | ||
77 | if test -z "$haveit"; then | ||
78 | if test -d "$additional_includedir"; then | ||
79 | dnl Really add $additional_includedir to $CPPFLAGS. | ||
80 | CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" | ||
81 | fi | ||
82 | fi | ||
83 | fi | ||
84 | fi | ||
85 | dnl Potentially add $additional_libdir to $LDFLAGS. | ||
86 | dnl But don't add it | ||
87 | dnl 1. if it's the standard /usr/lib, | ||
88 | dnl 2. if it's already present in $LDFLAGS, | ||
89 | dnl 3. if it's /usr/local/lib and we are using GCC on Linux, | ||
90 | dnl 4. if it doesn't exist as a directory. | ||
91 | if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then | ||
92 | haveit= | ||
93 | for x in $LDFLAGS; do | ||
94 | AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) | ||
95 | if test "X$x" = "X-L$additional_libdir"; then | ||
96 | haveit=yes | ||
97 | break | ||
98 | fi | ||
99 | done | ||
100 | if test -z "$haveit"; then | ||
101 | if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then | ||
102 | if test -n "$GCC"; then | ||
103 | case $host_os in | ||
104 | linux*) haveit=yes;; | ||
105 | esac | ||
106 | fi | ||
107 | fi | ||
108 | if test -z "$haveit"; then | ||
109 | if test -d "$additional_libdir"; then | ||
110 | dnl Really add $additional_libdir to $LDFLAGS. | ||
111 | LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" | ||
112 | fi | ||
113 | fi | ||
114 | fi | ||
115 | fi | ||
116 | fi | ||
117 | ]) | ||
118 | |||
119 | dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, | ||
120 | dnl acl_final_exec_prefix, containing the values to which $prefix and | ||
121 | dnl $exec_prefix will expand at the end of the configure script. | ||
122 | AC_DEFUN([AC_LIB_PREPARE_PREFIX], | ||
123 | [ | ||
124 | dnl Unfortunately, prefix and exec_prefix get only finally determined | ||
125 | dnl at the end of configure. | ||
126 | if test "X$prefix" = "XNONE"; then | ||
127 | acl_final_prefix="$ac_default_prefix" | ||
128 | else | ||
129 | acl_final_prefix="$prefix" | ||
130 | fi | ||
131 | if test "X$exec_prefix" = "XNONE"; then | ||
132 | acl_final_exec_prefix='${prefix}' | ||
133 | else | ||
134 | acl_final_exec_prefix="$exec_prefix" | ||
135 | fi | ||
136 | acl_save_prefix="$prefix" | ||
137 | prefix="$acl_final_prefix" | ||
138 | eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" | ||
139 | prefix="$acl_save_prefix" | ||
140 | ]) | ||
141 | |||
142 | dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the | ||
143 | dnl variables prefix and exec_prefix bound to the values they will have | ||
144 | dnl at the end of the configure script. | ||
145 | AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], | ||
146 | [ | ||
147 | acl_save_prefix="$prefix" | ||
148 | prefix="$acl_final_prefix" | ||
149 | acl_save_exec_prefix="$exec_prefix" | ||
150 | exec_prefix="$acl_final_exec_prefix" | ||
151 | $1 | ||
152 | exec_prefix="$acl_save_exec_prefix" | ||
153 | prefix="$acl_save_prefix" | ||
154 | ]) | ||
155 | |||
156 | dnl AC_LIB_PREPARE_MULTILIB creates a variable acl_libdirstem, containing | ||
157 | dnl the basename of the libdir, either "lib" or "lib64". | ||
158 | AC_DEFUN([AC_LIB_PREPARE_MULTILIB], | ||
159 | [ | ||
160 | dnl There is no formal standard regarding lib and lib64. The current | ||
161 | dnl practice is that on a system supporting 32-bit and 64-bit instruction | ||
162 | dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit | ||
163 | dnl libraries go under $prefix/lib. We determine the compiler's default | ||
164 | dnl mode by looking at the compiler's library search path. If at least | ||
165 | dnl of its elements ends in /lib64 or points to a directory whose absolute | ||
166 | dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the | ||
167 | dnl default, namely "lib". | ||
168 | acl_libdirstem=lib | ||
169 | searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` | ||
170 | if test -n "$searchpath"; then | ||
171 | acl_save_IFS="${IFS= }"; IFS=":" | ||
172 | for searchdir in $searchpath; do | ||
173 | if test -d "$searchdir"; then | ||
174 | case "$searchdir" in | ||
175 | */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; | ||
176 | *) searchdir=`cd "$searchdir" && pwd` | ||
177 | case "$searchdir" in | ||
178 | */lib64 ) acl_libdirstem=lib64 ;; | ||
179 | esac ;; | ||
180 | esac | ||
181 | fi | ||
182 | done | ||
183 | IFS="$acl_save_IFS" | ||
184 | fi | ||
185 | ]) | ||
diff --git a/gl/m4/lock.m4 b/gl/m4/lock.m4 new file mode 100644 index 00000000..0224f2ff --- /dev/null +++ b/gl/m4/lock.m4 | |||
@@ -0,0 +1,311 @@ | |||
1 | # lock.m4 serial 6 (gettext-0.16) | ||
2 | dnl Copyright (C) 2005-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | |||
9 | dnl Tests for a multithreading library to be used. | ||
10 | dnl Defines at most one of the macros USE_POSIX_THREADS, USE_SOLARIS_THREADS, | ||
11 | dnl USE_PTH_THREADS, USE_WIN32_THREADS | ||
12 | dnl Sets the variables LIBTHREAD and LTLIBTHREAD to the linker options for use | ||
13 | dnl in a Makefile (LIBTHREAD for use without libtool, LTLIBTHREAD for use with | ||
14 | dnl libtool). | ||
15 | dnl Sets the variables LIBMULTITHREAD and LTLIBMULTITHREAD similarly, for | ||
16 | dnl programs that really need multithread functionality. The difference | ||
17 | dnl between LIBTHREAD and LIBMULTITHREAD is that on platforms supporting weak | ||
18 | dnl symbols, typically LIBTHREAD="" whereas LIBMULTITHREAD="-lpthread". | ||
19 | dnl Adds to CPPFLAGS the flag -D_REENTRANT or -D_THREAD_SAFE if needed for | ||
20 | dnl multithread-safe programs. | ||
21 | |||
22 | AC_DEFUN([gl_LOCK_EARLY], | ||
23 | [ | ||
24 | AC_REQUIRE([gl_LOCK_EARLY_BODY]) | ||
25 | ]) | ||
26 | |||
27 | dnl The guts of gl_LOCK_EARLY. Needs to be expanded only once. | ||
28 | |||
29 | AC_DEFUN([gl_LOCK_EARLY_BODY], | ||
30 | [ | ||
31 | dnl Ordering constraints: This macro modifies CPPFLAGS in a way that | ||
32 | dnl influences the result of the autoconf tests that test for *_unlocked | ||
33 | dnl declarations, on AIX 5 at least. Therefore it must come early. | ||
34 | AC_BEFORE([$0], [gl_FUNC_GLIBC_UNLOCKED_IO])dnl | ||
35 | AC_BEFORE([$0], [gl_ARGP])dnl | ||
36 | |||
37 | AC_REQUIRE([AC_CANONICAL_HOST]) | ||
38 | AC_REQUIRE([AC_GNU_SOURCE]) dnl needed for pthread_rwlock_t on glibc systems | ||
39 | dnl Check for multithreading. | ||
40 | AC_ARG_ENABLE(threads, | ||
41 | AC_HELP_STRING([--enable-threads={posix|solaris|pth|win32}], [specify multithreading API]) | ||
42 | AC_HELP_STRING([--disable-threads], [build without multithread safety]), | ||
43 | [gl_use_threads=$enableval], | ||
44 | [case "$host_os" in | ||
45 | dnl Disable multithreading by default on OSF/1, because it interferes | ||
46 | dnl with fork()/exec(): When msgexec is linked with -lpthread, its child | ||
47 | dnl process gets an endless segmentation fault inside execvp(). | ||
48 | osf*) gl_use_threads=no ;; | ||
49 | *) gl_use_threads=yes ;; | ||
50 | esac | ||
51 | ]) | ||
52 | if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then | ||
53 | # For using <pthread.h>: | ||
54 | case "$host_os" in | ||
55 | osf*) | ||
56 | # On OSF/1, the compiler needs the flag -D_REENTRANT so that it | ||
57 | # groks <pthread.h>. cc also understands the flag -pthread, but | ||
58 | # we don't use it because 1. gcc-2.95 doesn't understand -pthread, | ||
59 | # 2. putting a flag into CPPFLAGS that has an effect on the linker | ||
60 | # causes the AC_TRY_LINK test below to succeed unexpectedly, | ||
61 | # leading to wrong values of LIBTHREAD and LTLIBTHREAD. | ||
62 | CPPFLAGS="$CPPFLAGS -D_REENTRANT" | ||
63 | ;; | ||
64 | esac | ||
65 | # Some systems optimize for single-threaded programs by default, and | ||
66 | # need special flags to disable these optimizations. For example, the | ||
67 | # definition of 'errno' in <errno.h>. | ||
68 | case "$host_os" in | ||
69 | aix* | freebsd*) CPPFLAGS="$CPPFLAGS -D_THREAD_SAFE" ;; | ||
70 | solaris*) CPPFLAGS="$CPPFLAGS -D_REENTRANT" ;; | ||
71 | esac | ||
72 | fi | ||
73 | ]) | ||
74 | |||
75 | dnl The guts of gl_LOCK. Needs to be expanded only once. | ||
76 | |||
77 | AC_DEFUN([gl_LOCK_BODY], | ||
78 | [ | ||
79 | AC_REQUIRE([gl_LOCK_EARLY_BODY]) | ||
80 | gl_threads_api=none | ||
81 | LIBTHREAD= | ||
82 | LTLIBTHREAD= | ||
83 | LIBMULTITHREAD= | ||
84 | LTLIBMULTITHREAD= | ||
85 | if test "$gl_use_threads" != no; then | ||
86 | dnl Check whether the compiler and linker support weak declarations. | ||
87 | AC_MSG_CHECKING([whether imported symbols can be declared weak]) | ||
88 | gl_have_weak=no | ||
89 | AC_TRY_LINK([extern void xyzzy (); | ||
90 | #pragma weak xyzzy], [xyzzy();], [gl_have_weak=yes]) | ||
91 | AC_MSG_RESULT([$gl_have_weak]) | ||
92 | if test "$gl_use_threads" = yes || test "$gl_use_threads" = posix; then | ||
93 | # On OSF/1, the compiler needs the flag -pthread or -D_REENTRANT so that | ||
94 | # it groks <pthread.h>. It's added above, in gl_LOCK_EARLY_BODY. | ||
95 | AC_CHECK_HEADER(pthread.h, gl_have_pthread_h=yes, gl_have_pthread_h=no) | ||
96 | if test "$gl_have_pthread_h" = yes; then | ||
97 | # Other possible tests: | ||
98 | # -lpthreads (FSU threads, PCthreads) | ||
99 | # -lgthreads | ||
100 | gl_have_pthread= | ||
101 | # Test whether both pthread_mutex_lock and pthread_mutexattr_init exist | ||
102 | # in libc. IRIX 6.5 has the first one in both libc and libpthread, but | ||
103 | # the second one only in libpthread, and lock.c needs it. | ||
104 | AC_TRY_LINK([#include <pthread.h>], | ||
105 | [pthread_mutex_lock((pthread_mutex_t*)0); | ||
106 | pthread_mutexattr_init((pthread_mutexattr_t*)0);], | ||
107 | [gl_have_pthread=yes]) | ||
108 | # Test for libpthread by looking for pthread_kill. (Not pthread_self, | ||
109 | # since it is defined as a macro on OSF/1.) | ||
110 | if test -n "$gl_have_pthread"; then | ||
111 | # The program links fine without libpthread. But it may actually | ||
112 | # need to link with libpthread in order to create multiple threads. | ||
113 | AC_CHECK_LIB(pthread, pthread_kill, | ||
114 | [LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread | ||
115 | # On Solaris and HP-UX, most pthread functions exist also in libc. | ||
116 | # Therefore pthread_in_use() needs to actually try to create a | ||
117 | # thread: pthread_create from libc will fail, whereas | ||
118 | # pthread_create will actually create a thread. | ||
119 | case "$host_os" in | ||
120 | solaris* | hpux*) | ||
121 | AC_DEFINE([PTHREAD_IN_USE_DETECTION_HARD], 1, | ||
122 | [Define if the pthread_in_use() detection is hard.]) | ||
123 | esac | ||
124 | ]) | ||
125 | else | ||
126 | # Some library is needed. Try libpthread and libc_r. | ||
127 | AC_CHECK_LIB(pthread, pthread_kill, | ||
128 | [gl_have_pthread=yes | ||
129 | LIBTHREAD=-lpthread LTLIBTHREAD=-lpthread | ||
130 | LIBMULTITHREAD=-lpthread LTLIBMULTITHREAD=-lpthread]) | ||
131 | if test -z "$gl_have_pthread"; then | ||
132 | # For FreeBSD 4. | ||
133 | AC_CHECK_LIB(c_r, pthread_kill, | ||
134 | [gl_have_pthread=yes | ||
135 | LIBTHREAD=-lc_r LTLIBTHREAD=-lc_r | ||
136 | LIBMULTITHREAD=-lc_r LTLIBMULTITHREAD=-lc_r]) | ||
137 | fi | ||
138 | fi | ||
139 | if test -n "$gl_have_pthread"; then | ||
140 | gl_threads_api=posix | ||
141 | AC_DEFINE([USE_POSIX_THREADS], 1, | ||
142 | [Define if the POSIX multithreading library can be used.]) | ||
143 | if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then | ||
144 | if test $gl_have_weak = yes; then | ||
145 | AC_DEFINE([USE_POSIX_THREADS_WEAK], 1, | ||
146 | [Define if references to the POSIX multithreading library should be made weak.]) | ||
147 | LIBTHREAD= | ||
148 | LTLIBTHREAD= | ||
149 | fi | ||
150 | fi | ||
151 | # OSF/1 4.0 and MacOS X 10.1 lack the pthread_rwlock_t type and the | ||
152 | # pthread_rwlock_* functions. | ||
153 | AC_CHECK_TYPE([pthread_rwlock_t], | ||
154 | [AC_DEFINE([HAVE_PTHREAD_RWLOCK], 1, | ||
155 | [Define if the POSIX multithreading library has read/write locks.])], | ||
156 | [], | ||
157 | [#include <pthread.h>]) | ||
158 | # glibc defines PTHREAD_MUTEX_RECURSIVE as enum, not as a macro. | ||
159 | AC_TRY_COMPILE([#include <pthread.h>], | ||
160 | [#if __FreeBSD__ == 4 | ||
161 | error "No, in FreeBSD 4.0 recursive mutexes actually don't work." | ||
162 | #else | ||
163 | int x = (int)PTHREAD_MUTEX_RECURSIVE; | ||
164 | return !x; | ||
165 | #endif], | ||
166 | [AC_DEFINE([HAVE_PTHREAD_MUTEX_RECURSIVE], 1, | ||
167 | [Define if the <pthread.h> defines PTHREAD_MUTEX_RECURSIVE.])]) | ||
168 | fi | ||
169 | fi | ||
170 | fi | ||
171 | if test -z "$gl_have_pthread"; then | ||
172 | if test "$gl_use_threads" = yes || test "$gl_use_threads" = solaris; then | ||
173 | gl_have_solaristhread= | ||
174 | gl_save_LIBS="$LIBS" | ||
175 | LIBS="$LIBS -lthread" | ||
176 | AC_TRY_LINK([#include <thread.h> | ||
177 | #include <synch.h>], | ||
178 | [thr_self();], | ||
179 | [gl_have_solaristhread=yes]) | ||
180 | LIBS="$gl_save_LIBS" | ||
181 | if test -n "$gl_have_solaristhread"; then | ||
182 | gl_threads_api=solaris | ||
183 | LIBTHREAD=-lthread | ||
184 | LTLIBTHREAD=-lthread | ||
185 | LIBMULTITHREAD="$LIBTHREAD" | ||
186 | LTLIBMULTITHREAD="$LTLIBTHREAD" | ||
187 | AC_DEFINE([USE_SOLARIS_THREADS], 1, | ||
188 | [Define if the old Solaris multithreading library can be used.]) | ||
189 | if test $gl_have_weak = yes; then | ||
190 | AC_DEFINE([USE_SOLARIS_THREADS_WEAK], 1, | ||
191 | [Define if references to the old Solaris multithreading library should be made weak.]) | ||
192 | LIBTHREAD= | ||
193 | LTLIBTHREAD= | ||
194 | fi | ||
195 | fi | ||
196 | fi | ||
197 | fi | ||
198 | if test "$gl_use_threads" = pth; then | ||
199 | gl_save_CPPFLAGS="$CPPFLAGS" | ||
200 | AC_LIB_LINKFLAGS(pth) | ||
201 | gl_have_pth= | ||
202 | gl_save_LIBS="$LIBS" | ||
203 | LIBS="$LIBS -lpth" | ||
204 | AC_TRY_LINK([#include <pth.h>], [pth_self();], gl_have_pth=yes) | ||
205 | LIBS="$gl_save_LIBS" | ||
206 | if test -n "$gl_have_pth"; then | ||
207 | gl_threads_api=pth | ||
208 | LIBTHREAD="$LIBPTH" | ||
209 | LTLIBTHREAD="$LTLIBPTH" | ||
210 | LIBMULTITHREAD="$LIBTHREAD" | ||
211 | LTLIBMULTITHREAD="$LTLIBTHREAD" | ||
212 | AC_DEFINE([USE_PTH_THREADS], 1, | ||
213 | [Define if the GNU Pth multithreading library can be used.]) | ||
214 | if test -n "$LIBMULTITHREAD" || test -n "$LTLIBMULTITHREAD"; then | ||
215 | if test $gl_have_weak = yes; then | ||
216 | AC_DEFINE([USE_PTH_THREADS_WEAK], 1, | ||
217 | [Define if references to the GNU Pth multithreading library should be made weak.]) | ||
218 | LIBTHREAD= | ||
219 | LTLIBTHREAD= | ||
220 | fi | ||
221 | fi | ||
222 | else | ||
223 | CPPFLAGS="$gl_save_CPPFLAGS" | ||
224 | fi | ||
225 | fi | ||
226 | if test -z "$gl_have_pthread"; then | ||
227 | if test "$gl_use_threads" = yes || test "$gl_use_threads" = win32; then | ||
228 | if { case "$host_os" in | ||
229 | mingw*) true;; | ||
230 | *) false;; | ||
231 | esac | ||
232 | }; then | ||
233 | gl_threads_api=win32 | ||
234 | AC_DEFINE([USE_WIN32_THREADS], 1, | ||
235 | [Define if the Win32 multithreading API can be used.]) | ||
236 | fi | ||
237 | fi | ||
238 | fi | ||
239 | fi | ||
240 | AC_MSG_CHECKING([for multithread API to use]) | ||
241 | AC_MSG_RESULT([$gl_threads_api]) | ||
242 | AC_SUBST(LIBTHREAD) | ||
243 | AC_SUBST(LTLIBTHREAD) | ||
244 | AC_SUBST(LIBMULTITHREAD) | ||
245 | AC_SUBST(LTLIBMULTITHREAD) | ||
246 | ]) | ||
247 | |||
248 | AC_DEFUN([gl_LOCK], | ||
249 | [ | ||
250 | AC_REQUIRE([gl_LOCK_EARLY]) | ||
251 | AC_REQUIRE([gl_LOCK_BODY]) | ||
252 | gl_PREREQ_LOCK | ||
253 | ]) | ||
254 | |||
255 | # Prerequisites of lib/lock.c. | ||
256 | AC_DEFUN([gl_PREREQ_LOCK], [ | ||
257 | AC_REQUIRE([AC_C_INLINE]) | ||
258 | ]) | ||
259 | |||
260 | dnl Survey of platforms: | ||
261 | dnl | ||
262 | dnl Platform Available Compiler Supports test-lock | ||
263 | dnl flavours option weak result | ||
264 | dnl --------------- --------- --------- -------- --------- | ||
265 | dnl Linux 2.4/glibc posix -lpthread Y OK | ||
266 | dnl | ||
267 | dnl GNU Hurd/glibc posix | ||
268 | dnl | ||
269 | dnl FreeBSD 5.3 posix -lc_r Y | ||
270 | dnl posix -lkse ? Y | ||
271 | dnl posix -lpthread ? Y | ||
272 | dnl posix -lthr Y | ||
273 | dnl | ||
274 | dnl FreeBSD 5.2 posix -lc_r Y | ||
275 | dnl posix -lkse Y | ||
276 | dnl posix -lthr Y | ||
277 | dnl | ||
278 | dnl FreeBSD 4.0,4.10 posix -lc_r Y OK | ||
279 | dnl | ||
280 | dnl NetBSD 1.6 -- | ||
281 | dnl | ||
282 | dnl OpenBSD 3.4 posix -lpthread Y OK | ||
283 | dnl | ||
284 | dnl MacOS X 10.[123] posix -lpthread Y OK | ||
285 | dnl | ||
286 | dnl Solaris 7,8,9 posix -lpthread Y Sol 7,8: 0.0; Sol 9: OK | ||
287 | dnl solaris -lthread Y Sol 7,8: 0.0; Sol 9: OK | ||
288 | dnl | ||
289 | dnl HP-UX 11 posix -lpthread N (cc) OK | ||
290 | dnl Y (gcc) | ||
291 | dnl | ||
292 | dnl IRIX 6.5 posix -lpthread Y 0.5 | ||
293 | dnl | ||
294 | dnl AIX 4.3,5.1 posix -lpthread N AIX 4: 0.5; AIX 5: OK | ||
295 | dnl | ||
296 | dnl OSF/1 4.0,5.1 posix -pthread (cc) N OK | ||
297 | dnl -lpthread (gcc) Y | ||
298 | dnl | ||
299 | dnl Cygwin posix -lpthread Y OK | ||
300 | dnl | ||
301 | dnl Any of the above pth -lpth 0.0 | ||
302 | dnl | ||
303 | dnl Mingw win32 N OK | ||
304 | dnl | ||
305 | dnl BeOS 5 -- | ||
306 | dnl | ||
307 | dnl The test-lock result shows what happens if in test-lock.c EXPLICIT_YIELD is | ||
308 | dnl turned off: | ||
309 | dnl OK if all three tests terminate OK, | ||
310 | dnl 0.5 if the first test terminates OK but the second one loops endlessly, | ||
311 | dnl 0.0 if the first test already loops endlessly. | ||
diff --git a/gl/m4/longdouble.m4 b/gl/m4/longdouble.m4 new file mode 100644 index 00000000..25590f47 --- /dev/null +++ b/gl/m4/longdouble.m4 | |||
@@ -0,0 +1,31 @@ | |||
1 | # longdouble.m4 serial 2 (gettext-0.15) | ||
2 | dnl Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | dnl Test whether the compiler supports the 'long double' type. | ||
9 | dnl Prerequisite: AC_PROG_CC | ||
10 | |||
11 | dnl This file is only needed in autoconf <= 2.59. Newer versions of autoconf | ||
12 | dnl have a macro AC_TYPE_LONG_DOUBLE with identical semantics. | ||
13 | |||
14 | AC_DEFUN([gt_TYPE_LONGDOUBLE], | ||
15 | [ | ||
16 | AC_CACHE_CHECK([for long double], gt_cv_c_long_double, | ||
17 | [if test "$GCC" = yes; then | ||
18 | gt_cv_c_long_double=yes | ||
19 | else | ||
20 | AC_TRY_COMPILE([ | ||
21 | /* The Stardent Vistra knows sizeof(long double), but does not support it. */ | ||
22 | long double foo = 0.0; | ||
23 | /* On Ultrix 4.3 cc, long double is 4 and double is 8. */ | ||
24 | int array [2*(sizeof(long double) >= sizeof(double)) - 1]; | ||
25 | ], , | ||
26 | gt_cv_c_long_double=yes, gt_cv_c_long_double=no) | ||
27 | fi]) | ||
28 | if test $gt_cv_c_long_double = yes; then | ||
29 | AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the 'long double' type.]) | ||
30 | fi | ||
31 | ]) | ||
diff --git a/gl/m4/longlong.m4 b/gl/m4/longlong.m4 new file mode 100644 index 00000000..1f9e862e --- /dev/null +++ b/gl/m4/longlong.m4 | |||
@@ -0,0 +1,72 @@ | |||
1 | # longlong.m4 serial 10 | ||
2 | dnl Copyright (C) 1999-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Paul Eggert. | ||
8 | |||
9 | # Define HAVE_LONG_LONG_INT if 'long long int' works. | ||
10 | # This fixes a bug in Autoconf 2.60, but can be removed once we | ||
11 | # assume 2.61 everywhere. | ||
12 | |||
13 | # Note: If the type 'long long int' exists but is only 32 bits large | ||
14 | # (as on some very old compilers), HAVE_LONG_LONG_INT will not be | ||
15 | # defined. In this case you can treat 'long long int' like 'long int'. | ||
16 | |||
17 | AC_DEFUN([AC_TYPE_LONG_LONG_INT], | ||
18 | [ | ||
19 | AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int], | ||
20 | [AC_LINK_IFELSE( | ||
21 | [AC_LANG_PROGRAM( | ||
22 | [[long long int ll = 9223372036854775807ll; | ||
23 | long long int nll = -9223372036854775807LL; | ||
24 | typedef int a[((-9223372036854775807LL < 0 | ||
25 | && 0 < 9223372036854775807ll) | ||
26 | ? 1 : -1)]; | ||
27 | int i = 63;]], | ||
28 | [[long long int llmax = 9223372036854775807ll; | ||
29 | return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) | ||
30 | | (llmax / ll) | (llmax % ll));]])], | ||
31 | [dnl This catches a bug in Tandem NonStop Kernel (OSS) cc -O circa 2004. | ||
32 | dnl If cross compiling, assume the bug isn't important, since | ||
33 | dnl nobody cross compiles for this platform as far as we know. | ||
34 | AC_RUN_IFELSE( | ||
35 | [AC_LANG_PROGRAM( | ||
36 | [[@%:@include <limits.h> | ||
37 | @%:@ifndef LLONG_MAX | ||
38 | @%:@ define HALF \ | ||
39 | (1LL << (sizeof (long long int) * CHAR_BIT - 2)) | ||
40 | @%:@ define LLONG_MAX (HALF - 1 + HALF) | ||
41 | @%:@endif]], | ||
42 | [[long long int n = 1; | ||
43 | int i; | ||
44 | for (i = 0; ; i++) | ||
45 | { | ||
46 | long long int m = n << i; | ||
47 | if (m >> i != n) | ||
48 | return 1; | ||
49 | if (LLONG_MAX / 2 < m) | ||
50 | break; | ||
51 | } | ||
52 | return 0;]])], | ||
53 | [ac_cv_type_long_long_int=yes], | ||
54 | [ac_cv_type_long_long_int=no], | ||
55 | [ac_cv_type_long_long_int=yes])], | ||
56 | [ac_cv_type_long_long_int=no])]) | ||
57 | if test $ac_cv_type_long_long_int = yes; then | ||
58 | AC_DEFINE([HAVE_LONG_LONG_INT], 1, | ||
59 | [Define to 1 if the system has the type `long long int'.]) | ||
60 | fi | ||
61 | ]) | ||
62 | |||
63 | # This macro is obsolescent and should go away soon. | ||
64 | AC_DEFUN([gl_AC_TYPE_LONG_LONG], | ||
65 | [ | ||
66 | AC_REQUIRE([AC_TYPE_LONG_LONG_INT]) | ||
67 | ac_cv_type_long_long=$ac_cv_type_long_long_int | ||
68 | if test $ac_cv_type_long_long = yes; then | ||
69 | AC_DEFINE(HAVE_LONG_LONG, 1, | ||
70 | [Define if you have the 'long long' type.]) | ||
71 | fi | ||
72 | ]) | ||
diff --git a/gl/m4/ls-mntd-fs.m4 b/gl/m4/ls-mntd-fs.m4 new file mode 100644 index 00000000..21ac4e74 --- /dev/null +++ b/gl/m4/ls-mntd-fs.m4 | |||
@@ -0,0 +1,337 @@ | |||
1 | #serial 26 | ||
2 | # How to list mounted file systems. | ||
3 | |||
4 | # Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 Free Software | ||
5 | # Foundation, Inc. | ||
6 | # | ||
7 | # This file is free software; the Free Software Foundation | ||
8 | # gives unlimited permission to copy and/or distribute it, | ||
9 | # with or without modifications, as long as this notice is preserved. | ||
10 | |||
11 | dnl From Jim Meyering. | ||
12 | dnl | ||
13 | dnl This is not pretty. I've just taken the autoconf code and wrapped | ||
14 | dnl it in an AC_DEFUN and made some other fixes. | ||
15 | dnl | ||
16 | |||
17 | # Replace Autoconf's AC_FUNC_GETMNTENT to work around a bug in Autoconf | ||
18 | # through Autoconf 2.59. We can remove this once we assume Autoconf 2.60 | ||
19 | # or later. | ||
20 | AC_DEFUN([AC_FUNC_GETMNTENT], | ||
21 | [# getmntent is in the standard C library on UNICOS, in -lsun on Irix 4, | ||
22 | # -lseq on Dynix/PTX, -lgen on Unixware. | ||
23 | AC_SEARCH_LIBS(getmntent, [sun seq gen]) | ||
24 | AC_CHECK_FUNCS(getmntent) | ||
25 | ]) | ||
26 | |||
27 | # gl_LIST_MOUNTED_FILE_SYSTEMS([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) | ||
28 | AC_DEFUN([gl_LIST_MOUNTED_FILE_SYSTEMS], | ||
29 | [ | ||
30 | AC_CHECK_FUNCS(listmntent getmntinfo) | ||
31 | AC_CHECK_HEADERS_ONCE(sys/param.h sys/statvfs.h) | ||
32 | |||
33 | # We must include grp.h before ucred.h on OSF V4.0, since ucred.h uses | ||
34 | # NGROUPS (as the array dimension for a struct member) without a definition. | ||
35 | AC_CHECK_HEADERS(sys/ucred.h, [], [], [#include <grp.h>]) | ||
36 | |||
37 | AC_CHECK_HEADERS(sys/mount.h, [], [], | ||
38 | [AC_INCLUDES_DEFAULT | ||
39 | [#if HAVE_SYS_PARAM_H | ||
40 | #include <sys/param.h> | ||
41 | #endif]]) | ||
42 | |||
43 | AC_CHECK_HEADERS(mntent.h sys/fs_types.h) | ||
44 | getfsstat_includes="\ | ||
45 | $ac_includes_default | ||
46 | #if HAVE_SYS_PARAM_H | ||
47 | # include <sys/param.h> /* needed by powerpc-apple-darwin1.3.7 */ | ||
48 | #endif | ||
49 | #if HAVE_SYS_UCRED_H | ||
50 | # include <grp.h> /* needed for definition of NGROUPS */ | ||
51 | # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */ | ||
52 | #endif | ||
53 | #if HAVE_SYS_MOUNT_H | ||
54 | # include <sys/mount.h> | ||
55 | #endif | ||
56 | #if HAVE_SYS_FS_TYPES_H | ||
57 | # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */ | ||
58 | #endif | ||
59 | " | ||
60 | AC_CHECK_MEMBERS([struct fsstat.f_fstypename],,,[$getfsstat_includes]) | ||
61 | |||
62 | # Determine how to get the list of mounted file systems. | ||
63 | ac_list_mounted_fs= | ||
64 | |||
65 | # If the getmntent function is available but not in the standard library, | ||
66 | # make sure LIBS contains the appropriate -l option. | ||
67 | AC_FUNC_GETMNTENT | ||
68 | |||
69 | # This test must precede the ones for getmntent because Unicos-9 is | ||
70 | # reported to have the getmntent function, but its support is incompatible | ||
71 | # with other getmntent implementations. | ||
72 | |||
73 | # NOTE: Normally, I wouldn't use a check for system type as I've done for | ||
74 | # `CRAY' below since that goes against the whole autoconf philosophy. But | ||
75 | # I think there is too great a chance that some non-Cray system has a | ||
76 | # function named listmntent to risk the false positive. | ||
77 | |||
78 | if test -z "$ac_list_mounted_fs"; then | ||
79 | # Cray UNICOS 9 | ||
80 | AC_MSG_CHECKING([for listmntent of Cray/Unicos-9]) | ||
81 | AC_CACHE_VAL(fu_cv_sys_mounted_cray_listmntent, | ||
82 | [fu_cv_sys_mounted_cray_listmntent=no | ||
83 | AC_EGREP_CPP(yes, | ||
84 | [#ifdef _CRAY | ||
85 | yes | ||
86 | #endif | ||
87 | ], [test $ac_cv_func_listmntent = yes \ | ||
88 | && fu_cv_sys_mounted_cray_listmntent=yes] | ||
89 | ) | ||
90 | ] | ||
91 | ) | ||
92 | AC_MSG_RESULT($fu_cv_sys_mounted_cray_listmntent) | ||
93 | if test $fu_cv_sys_mounted_cray_listmntent = yes; then | ||
94 | ac_list_mounted_fs=found | ||
95 | AC_DEFINE(MOUNTED_LISTMNTENT, 1, | ||
96 | [Define if there is a function named listmntent that can be used to | ||
97 | list all mounted file systems. (UNICOS)]) | ||
98 | fi | ||
99 | fi | ||
100 | |||
101 | if test -z "$ac_list_mounted_fs"; then | ||
102 | # AIX. | ||
103 | AC_MSG_CHECKING([for mntctl function and struct vmount]) | ||
104 | AC_CACHE_VAL(fu_cv_sys_mounted_vmount, | ||
105 | [AC_TRY_CPP([#include <fshelp.h>], | ||
106 | fu_cv_sys_mounted_vmount=yes, | ||
107 | fu_cv_sys_mounted_vmount=no)]) | ||
108 | AC_MSG_RESULT($fu_cv_sys_mounted_vmount) | ||
109 | if test $fu_cv_sys_mounted_vmount = yes; then | ||
110 | ac_list_mounted_fs=found | ||
111 | AC_DEFINE(MOUNTED_VMOUNT, 1, | ||
112 | [Define if there is a function named mntctl that can be used to read | ||
113 | the list of mounted file systems, and there is a system header file | ||
114 | that declares `struct vmount.' (AIX)]) | ||
115 | fi | ||
116 | fi | ||
117 | |||
118 | if test $ac_cv_func_getmntent = yes; then | ||
119 | |||
120 | # This system has the getmntent function. | ||
121 | # Determine whether it's the one-argument variant or the two-argument one. | ||
122 | |||
123 | if test -z "$ac_list_mounted_fs"; then | ||
124 | # 4.3BSD, SunOS, HP-UX, Dynix, Irix | ||
125 | AC_MSG_CHECKING([for one-argument getmntent function]) | ||
126 | AC_CACHE_VAL(fu_cv_sys_mounted_getmntent1, | ||
127 | [AC_TRY_COMPILE([ | ||
128 | /* SunOS 4.1.x /usr/include/mntent.h needs this for FILE */ | ||
129 | #include <stdio.h> | ||
130 | |||
131 | #include <mntent.h> | ||
132 | #if !defined MOUNTED | ||
133 | # if defined _PATH_MOUNTED /* GNU libc */ | ||
134 | # define MOUNTED _PATH_MOUNTED | ||
135 | # endif | ||
136 | # if defined MNT_MNTTAB /* HP-UX. */ | ||
137 | # define MOUNTED MNT_MNTTAB | ||
138 | # endif | ||
139 | # if defined MNTTABNAME /* Dynix. */ | ||
140 | # define MOUNTED MNTTABNAME | ||
141 | # endif | ||
142 | #endif | ||
143 | ], | ||
144 | [ struct mntent *mnt = 0; char *table = MOUNTED; | ||
145 | if (sizeof mnt && sizeof table) return 0;], | ||
146 | fu_cv_sys_mounted_getmntent1=yes, | ||
147 | fu_cv_sys_mounted_getmntent1=no)]) | ||
148 | AC_MSG_RESULT($fu_cv_sys_mounted_getmntent1) | ||
149 | if test $fu_cv_sys_mounted_getmntent1 = yes; then | ||
150 | ac_list_mounted_fs=found | ||
151 | AC_DEFINE(MOUNTED_GETMNTENT1, 1, | ||
152 | [Define if there is a function named getmntent for reading the list | ||
153 | of mounted file systems, and that function takes a single argument. | ||
154 | (4.3BSD, SunOS, HP-UX, Dynix, Irix)]) | ||
155 | fi | ||
156 | fi | ||
157 | |||
158 | if test -z "$ac_list_mounted_fs"; then | ||
159 | # SVR4 | ||
160 | AC_MSG_CHECKING([for two-argument getmntent function]) | ||
161 | AC_CACHE_VAL(fu_cv_sys_mounted_getmntent2, | ||
162 | [AC_EGREP_HEADER(getmntent, sys/mnttab.h, | ||
163 | fu_cv_sys_mounted_getmntent2=yes, | ||
164 | fu_cv_sys_mounted_getmntent2=no)]) | ||
165 | AC_MSG_RESULT($fu_cv_sys_mounted_getmntent2) | ||
166 | if test $fu_cv_sys_mounted_getmntent2 = yes; then | ||
167 | ac_list_mounted_fs=found | ||
168 | AC_DEFINE(MOUNTED_GETMNTENT2, 1, | ||
169 | [Define if there is a function named getmntent for reading the list of | ||
170 | mounted file systems, and that function takes two arguments. (SVR4)]) | ||
171 | AC_CHECK_FUNCS(hasmntopt) | ||
172 | fi | ||
173 | fi | ||
174 | |||
175 | fi | ||
176 | |||
177 | if test -z "$ac_list_mounted_fs"; then | ||
178 | # DEC Alpha running OSF/1, and Apple Darwin 1.3. | ||
179 | # powerpc-apple-darwin1.3.7 needs sys/param.h sys/ucred.h sys/fs_types.h | ||
180 | |||
181 | AC_MSG_CHECKING([for getfsstat function]) | ||
182 | AC_CACHE_VAL(fu_cv_sys_mounted_getfsstat, | ||
183 | [AC_TRY_LINK([ | ||
184 | #include <sys/types.h> | ||
185 | #if HAVE_STRUCT_FSSTAT_F_FSTYPENAME | ||
186 | # define FS_TYPE(Ent) ((Ent).f_fstypename) | ||
187 | #else | ||
188 | # define FS_TYPE(Ent) mnt_names[(Ent).f_type] | ||
189 | #endif | ||
190 | ]$getfsstat_includes | ||
191 | , | ||
192 | [struct statfs *stats; | ||
193 | int numsys = getfsstat ((struct statfs *)0, 0L, MNT_WAIT); | ||
194 | char *t = FS_TYPE (*stats); ], | ||
195 | fu_cv_sys_mounted_getfsstat=yes, | ||
196 | fu_cv_sys_mounted_getfsstat=no)]) | ||
197 | AC_MSG_RESULT($fu_cv_sys_mounted_getfsstat) | ||
198 | if test $fu_cv_sys_mounted_getfsstat = yes; then | ||
199 | ac_list_mounted_fs=found | ||
200 | AC_DEFINE(MOUNTED_GETFSSTAT, 1, | ||
201 | [Define if there is a function named getfsstat for reading the | ||
202 | list of mounted file systems. (DEC Alpha running OSF/1)]) | ||
203 | fi | ||
204 | fi | ||
205 | |||
206 | if test -z "$ac_list_mounted_fs"; then | ||
207 | # SVR3 | ||
208 | AC_MSG_CHECKING([for FIXME existence of three headers]) | ||
209 | AC_CACHE_VAL(fu_cv_sys_mounted_fread_fstyp, | ||
210 | [AC_TRY_CPP([ | ||
211 | #include <sys/statfs.h> | ||
212 | #include <sys/fstyp.h> | ||
213 | #include <mnttab.h>], | ||
214 | fu_cv_sys_mounted_fread_fstyp=yes, | ||
215 | fu_cv_sys_mounted_fread_fstyp=no)]) | ||
216 | AC_MSG_RESULT($fu_cv_sys_mounted_fread_fstyp) | ||
217 | if test $fu_cv_sys_mounted_fread_fstyp = yes; then | ||
218 | ac_list_mounted_fs=found | ||
219 | AC_DEFINE(MOUNTED_FREAD_FSTYP, 1, | ||
220 | [Define if (like SVR2) there is no specific function for reading the | ||
221 | list of mounted file systems, and your system has these header files: | ||
222 | <sys/fstyp.h> and <sys/statfs.h>. (SVR3)]) | ||
223 | fi | ||
224 | fi | ||
225 | |||
226 | if test -z "$ac_list_mounted_fs"; then | ||
227 | # 4.4BSD and DEC OSF/1. | ||
228 | AC_MSG_CHECKING([for getmntinfo function]) | ||
229 | AC_CACHE_VAL(fu_cv_sys_mounted_getmntinfo, | ||
230 | [ | ||
231 | test "$ac_cv_func_getmntinfo" = yes \ | ||
232 | && fu_cv_sys_mounted_getmntinfo=yes \ | ||
233 | || fu_cv_sys_mounted_getmntinfo=no | ||
234 | ]) | ||
235 | AC_MSG_RESULT($fu_cv_sys_mounted_getmntinfo) | ||
236 | if test $fu_cv_sys_mounted_getmntinfo = yes; then | ||
237 | AC_MSG_CHECKING([whether getmntinfo returns statvfs structures]) | ||
238 | AC_CACHE_VAL(fu_cv_sys_mounted_getmntinfo2, | ||
239 | [ | ||
240 | AC_TRY_COMPILE([ | ||
241 | #if HAVE_SYS_PARAM_H | ||
242 | # include <sys/param.h> | ||
243 | #endif | ||
244 | #include <sys/types.h> | ||
245 | #if HAVE_SYS_MOUNT_H | ||
246 | # include <sys/mount.h> | ||
247 | #endif | ||
248 | #if HAVE_SYS_STATVFS_H | ||
249 | # include <sys/statvfs.h> | ||
250 | #endif | ||
251 | extern int getmntinfo (struct statfs **, int); | ||
252 | ], [], | ||
253 | [fu_cv_sys_mounted_getmntinfo2=no], | ||
254 | [fu_cv_sys_mounted_getmntinfo2=yes]) | ||
255 | ]) | ||
256 | AC_MSG_RESULT([$fu_cv_sys_mounted_getmntinfo2]) | ||
257 | if test $fu_cv_sys_mounted_getmntinfo2 = no; then | ||
258 | ac_list_mounted_fs=found | ||
259 | AC_DEFINE(MOUNTED_GETMNTINFO, 1, | ||
260 | [Define if there is a function named getmntinfo for reading the | ||
261 | list of mounted file systems and it returns an array of | ||
262 | 'struct statfs'. (4.4BSD, Darwin)]) | ||
263 | else | ||
264 | ac_list_mounted_fs=found | ||
265 | AC_DEFINE(MOUNTED_GETMNTINFO2, 1, | ||
266 | [Define if there is a function named getmntinfo for reading the | ||
267 | list of mounted file systems and it returns an array of | ||
268 | 'struct statvfs'. (NetBSD 3.0)]) | ||
269 | fi | ||
270 | fi | ||
271 | fi | ||
272 | |||
273 | if test -z "$ac_list_mounted_fs"; then | ||
274 | # Ultrix | ||
275 | AC_MSG_CHECKING([for getmnt function]) | ||
276 | AC_CACHE_VAL(fu_cv_sys_mounted_getmnt, | ||
277 | [AC_TRY_CPP([ | ||
278 | #include <sys/fs_types.h> | ||
279 | #include <sys/mount.h>], | ||
280 | fu_cv_sys_mounted_getmnt=yes, | ||
281 | fu_cv_sys_mounted_getmnt=no)]) | ||
282 | AC_MSG_RESULT($fu_cv_sys_mounted_getmnt) | ||
283 | if test $fu_cv_sys_mounted_getmnt = yes; then | ||
284 | ac_list_mounted_fs=found | ||
285 | AC_DEFINE(MOUNTED_GETMNT, 1, | ||
286 | [Define if there is a function named getmnt for reading the list of | ||
287 | mounted file systems. (Ultrix)]) | ||
288 | fi | ||
289 | fi | ||
290 | |||
291 | if test -z "$ac_list_mounted_fs"; then | ||
292 | # BeOS | ||
293 | AC_CHECK_FUNCS(next_dev fs_stat_dev) | ||
294 | AC_CHECK_HEADERS(fs_info.h) | ||
295 | AC_MSG_CHECKING([for BEOS mounted file system support functions]) | ||
296 | if test $ac_cv_header_fs_info_h = yes \ | ||
297 | && test $ac_cv_func_next_dev = yes \ | ||
298 | && test $ac_cv_func_fs_stat_dev = yes; then | ||
299 | fu_result=yes | ||
300 | else | ||
301 | fu_result=no | ||
302 | fi | ||
303 | AC_MSG_RESULT($fu_result) | ||
304 | if test $fu_result = yes; then | ||
305 | ac_list_mounted_fs=found | ||
306 | AC_DEFINE(MOUNTED_FS_STAT_DEV, 1, | ||
307 | [Define if there are functions named next_dev and fs_stat_dev for | ||
308 | reading the list of mounted file systems. (BeOS)]) | ||
309 | fi | ||
310 | fi | ||
311 | |||
312 | if test -z "$ac_list_mounted_fs"; then | ||
313 | # SVR2 | ||
314 | AC_MSG_CHECKING([whether it is possible to resort to fread on /etc/mnttab]) | ||
315 | AC_CACHE_VAL(fu_cv_sys_mounted_fread, | ||
316 | [AC_TRY_CPP([#include <mnttab.h>], | ||
317 | fu_cv_sys_mounted_fread=yes, | ||
318 | fu_cv_sys_mounted_fread=no)]) | ||
319 | AC_MSG_RESULT($fu_cv_sys_mounted_fread) | ||
320 | if test $fu_cv_sys_mounted_fread = yes; then | ||
321 | ac_list_mounted_fs=found | ||
322 | AC_DEFINE(MOUNTED_FREAD, 1, | ||
323 | [Define if there is no specific function for reading the list of | ||
324 | mounted file systems. fread will be used to read /etc/mnttab. | ||
325 | (SVR2) ]) | ||
326 | fi | ||
327 | fi | ||
328 | |||
329 | if test -z "$ac_list_mounted_fs"; then | ||
330 | AC_MSG_ERROR([could not determine how to read list of mounted file systems]) | ||
331 | # FIXME -- no need to abort building the whole package | ||
332 | # Can't build mountlist.c or anything that needs its functions | ||
333 | fi | ||
334 | |||
335 | AS_IF([test $ac_list_mounted_fs = found], [$1], [$2]) | ||
336 | |||
337 | ]) | ||
diff --git a/gl/m4/mbchar.m4 b/gl/m4/mbchar.m4 new file mode 100644 index 00000000..5380941b --- /dev/null +++ b/gl/m4/mbchar.m4 | |||
@@ -0,0 +1,14 @@ | |||
1 | # mbchar.m4 serial 5 | ||
2 | dnl Copyright (C) 2005-2007 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl autoconf tests required for use of mbchar.m4 | ||
8 | dnl From Bruno Haible. | ||
9 | |||
10 | AC_DEFUN([gl_MBCHAR], | ||
11 | [ | ||
12 | AC_REQUIRE([AC_GNU_SOURCE]) | ||
13 | AC_LIBOBJ([mbchar]) | ||
14 | ]) | ||
diff --git a/gl/m4/mbiter.m4 b/gl/m4/mbiter.m4 new file mode 100644 index 00000000..7d51af10 --- /dev/null +++ b/gl/m4/mbiter.m4 | |||
@@ -0,0 +1,17 @@ | |||
1 | # mbiter.m4 serial 2 | ||
2 | dnl Copyright (C) 2005 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl autoconf tests required for use of mbiter.h | ||
8 | dnl From Bruno Haible. | ||
9 | |||
10 | AC_DEFUN([gl_MBITER], | ||
11 | [ | ||
12 | AC_REQUIRE([AC_TYPE_MBSTATE_T]) | ||
13 | dnl The following line is that so the user can test HAVE_MBRTOWC before | ||
14 | dnl #include "mbiter.h" or "mbuiter.h". | ||
15 | AC_REQUIRE([gl_FUNC_MBRTOWC]) | ||
16 | : | ||
17 | ]) | ||
diff --git a/gl/m4/mbrtowc.m4 b/gl/m4/mbrtowc.m4 new file mode 100644 index 00000000..a3bd9114 --- /dev/null +++ b/gl/m4/mbrtowc.m4 | |||
@@ -0,0 +1,31 @@ | |||
1 | # mbrtowc.m4 serial 8 | ||
2 | dnl Copyright (C) 2001-2002, 2004-2005 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Paul Eggert | ||
8 | |||
9 | dnl This file can be removed, and gl_FUNC_MBRTOWC replaced with | ||
10 | dnl AC_FUNC_MBRTOWC, when autoconf 2.60 can be assumed everywhere. | ||
11 | |||
12 | AC_DEFUN([gl_FUNC_MBRTOWC], | ||
13 | [ | ||
14 | dnl Same as AC_FUNC_MBRTOWC in autoconf-2.60. | ||
15 | AC_CACHE_CHECK([whether mbrtowc and mbstate_t are properly declared], | ||
16 | gl_cv_func_mbrtowc, | ||
17 | [AC_LINK_IFELSE( | ||
18 | [AC_LANG_PROGRAM( | ||
19 | [[#include <wchar.h>]], | ||
20 | [[wchar_t wc; | ||
21 | char const s[] = ""; | ||
22 | size_t n = 1; | ||
23 | mbstate_t state; | ||
24 | return ! (sizeof state && (mbrtowc) (&wc, s, n, &state));]])], | ||
25 | gl_cv_func_mbrtowc=yes, | ||
26 | gl_cv_func_mbrtowc=no)]) | ||
27 | if test $gl_cv_func_mbrtowc = yes; then | ||
28 | AC_DEFINE([HAVE_MBRTOWC], 1, | ||
29 | [Define to 1 if mbrtowc and mbstate_t are properly declared.]) | ||
30 | fi | ||
31 | ]) | ||
diff --git a/gl/m4/memchr.m4 b/gl/m4/memchr.m4 new file mode 100644 index 00000000..91b8636e --- /dev/null +++ b/gl/m4/memchr.m4 | |||
@@ -0,0 +1,18 @@ | |||
1 | # memchr.m4 serial 4 | ||
2 | dnl Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FUNC_MEMCHR], | ||
8 | [ | ||
9 | AC_REPLACE_FUNCS(memchr) | ||
10 | if test $ac_cv_func_memchr = no; then | ||
11 | gl_PREREQ_MEMCHR | ||
12 | fi | ||
13 | ]) | ||
14 | |||
15 | # Prerequisites of lib/memchr.c. | ||
16 | AC_DEFUN([gl_PREREQ_MEMCHR], [ | ||
17 | AC_CHECK_HEADERS(bp-sym.h) | ||
18 | ]) | ||
diff --git a/gl/m4/minmax.m4 b/gl/m4/minmax.m4 new file mode 100644 index 00000000..bbd1ba0b --- /dev/null +++ b/gl/m4/minmax.m4 | |||
@@ -0,0 +1,41 @@ | |||
1 | # minmax.m4 serial 2 | ||
2 | dnl Copyright (C) 2005 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_PREREQ(2.52) | ||
8 | |||
9 | AC_DEFUN([gl_MINMAX], | ||
10 | [ | ||
11 | AC_REQUIRE([gl_PREREQ_MINMAX]) | ||
12 | ]) | ||
13 | |||
14 | # Prerequisites of lib/minmax.h. | ||
15 | AC_DEFUN([gl_PREREQ_MINMAX], | ||
16 | [ | ||
17 | gl_MINMAX_IN_HEADER([limits.h]) | ||
18 | gl_MINMAX_IN_HEADER([sys/param.h]) | ||
19 | ]) | ||
20 | |||
21 | dnl gl_MINMAX_IN_HEADER(HEADER) | ||
22 | dnl The parameter has to be a literal header name; it cannot be macro, | ||
23 | dnl nor a shell variable. (Because autoheader collects only AC_DEFINE | ||
24 | dnl invocations with a literal macro name.) | ||
25 | AC_DEFUN([gl_MINMAX_IN_HEADER], | ||
26 | [ | ||
27 | m4_pushdef([header], AS_TR_SH([$1])) | ||
28 | m4_pushdef([HEADER], AS_TR_CPP([$1])) | ||
29 | AC_CACHE_CHECK([whether <$1> defines MIN and MAX], | ||
30 | [gl_cv_minmax_in_]header, | ||
31 | [AC_TRY_COMPILE([#include <$1> | ||
32 | int x = MIN (42, 17);], [], | ||
33 | [gl_cv_minmax_in_]header[=yes], | ||
34 | [gl_cv_minmax_in_]header[=no])]) | ||
35 | if test $gl_cv_minmax_in_[]header = yes; then | ||
36 | AC_DEFINE([HAVE_MINMAX_IN_]HEADER, 1, | ||
37 | [Define to 1 if <$1> defines the MIN and MAX macros.]) | ||
38 | fi | ||
39 | m4_popdef([HEADER]) | ||
40 | m4_popdef([header]) | ||
41 | ]) | ||
diff --git a/gl/m4/mountlist.m4 b/gl/m4/mountlist.m4 new file mode 100644 index 00000000..c25f44e7 --- /dev/null +++ b/gl/m4/mountlist.m4 | |||
@@ -0,0 +1,23 @@ | |||
1 | #serial 9 | ||
2 | dnl Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_MOUNTLIST], | ||
8 | [ | ||
9 | gl_LIST_MOUNTED_FILE_SYSTEMS([gl_cv_list_mounted_fs=yes], | ||
10 | [gl_cv_list_mounted_fs=no]) | ||
11 | if test $gl_cv_list_mounted_fs = yes; then | ||
12 | AC_LIBOBJ(mountlist) | ||
13 | gl_PREREQ_MOUNTLIST_EXTRA | ||
14 | fi | ||
15 | ]) | ||
16 | |||
17 | # Prerequisites of lib/mountlist.c not done by gl_LIST_MOUNTED_FILE_SYSTEMS. | ||
18 | AC_DEFUN([gl_PREREQ_MOUNTLIST_EXTRA], | ||
19 | [ | ||
20 | dnl Note gl_LIST_MOUNTED_FILE_SYSTEMS checks for mntent.h, not sys/mntent.h. | ||
21 | AC_CHECK_HEADERS(sys/mntent.h) | ||
22 | gl_FSTYPENAME | ||
23 | ]) | ||
diff --git a/gl/m4/netinet_in_h.m4 b/gl/m4/netinet_in_h.m4 new file mode 100644 index 00000000..d73531a0 --- /dev/null +++ b/gl/m4/netinet_in_h.m4 | |||
@@ -0,0 +1,18 @@ | |||
1 | # netinet_in_h.m4 serial 1 | ||
2 | dnl Copyright (C) 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl Written by Simon Josefsson | ||
8 | |||
9 | AC_DEFUN([gl_HEADER_NETINET_IN], | ||
10 | [ | ||
11 | AC_CHECK_HEADERS_ONCE([netinet/in.h]) | ||
12 | if test $ac_cv_header_netinet_in_h = yes; then | ||
13 | NETINET_IN_H='' | ||
14 | else | ||
15 | NETINET_IN_H='netinet/in.h' | ||
16 | fi | ||
17 | AC_SUBST(NETINET_IN_H) | ||
18 | ]) | ||
diff --git a/gl/m4/nls.m4 b/gl/m4/nls.m4 new file mode 100644 index 00000000..7967cc2f --- /dev/null +++ b/gl/m4/nls.m4 | |||
@@ -0,0 +1,31 @@ | |||
1 | # nls.m4 serial 3 (gettext-0.15) | ||
2 | dnl Copyright (C) 1995-2003, 2005-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | dnl | ||
7 | dnl This file can can be used in projects which are not available under | ||
8 | dnl the GNU General Public License or the GNU Library General Public | ||
9 | dnl License but which still want to provide support for the GNU gettext | ||
10 | dnl functionality. | ||
11 | dnl Please note that the actual code of the GNU gettext library is covered | ||
12 | dnl by the GNU Library General Public License, and the rest of the GNU | ||
13 | dnl gettext package package is covered by the GNU General Public License. | ||
14 | dnl They are *not* in the public domain. | ||
15 | |||
16 | dnl Authors: | ||
17 | dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. | ||
18 | dnl Bruno Haible <haible@clisp.cons.org>, 2000-2003. | ||
19 | |||
20 | AC_PREREQ(2.50) | ||
21 | |||
22 | AC_DEFUN([AM_NLS], | ||
23 | [ | ||
24 | AC_MSG_CHECKING([whether NLS is requested]) | ||
25 | dnl Default is enabled NLS | ||
26 | AC_ARG_ENABLE(nls, | ||
27 | [ --disable-nls do not use Native Language Support], | ||
28 | USE_NLS=$enableval, USE_NLS=yes) | ||
29 | AC_MSG_RESULT($USE_NLS) | ||
30 | AC_SUBST(USE_NLS) | ||
31 | ]) | ||
diff --git a/gl/m4/onceonly_2_57.m4 b/gl/m4/onceonly_2_57.m4 new file mode 100644 index 00000000..15884b3e --- /dev/null +++ b/gl/m4/onceonly_2_57.m4 | |||
@@ -0,0 +1,86 @@ | |||
1 | # onceonly_2_57.m4 serial 4 | ||
2 | dnl Copyright (C) 2002-2003, 2005-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software, distributed under the terms of the GNU | ||
4 | dnl General Public License. As a special exception to the GNU General | ||
5 | dnl Public License, this file may be distributed as part of a program | ||
6 | dnl that contains a configuration script generated by Autoconf, under | ||
7 | dnl the same distribution terms as the rest of that program. | ||
8 | |||
9 | dnl This file defines some "once only" variants of standard autoconf macros. | ||
10 | dnl AC_CHECK_HEADERS_ONCE like AC_CHECK_HEADERS | ||
11 | dnl AC_CHECK_FUNCS_ONCE like AC_CHECK_FUNCS | ||
12 | dnl AC_CHECK_DECLS_ONCE like AC_CHECK_DECLS | ||
13 | dnl AC_REQUIRE([AC_FUNC_STRCOLL]) like AC_FUNC_STRCOLL | ||
14 | dnl The advantage is that the check for each of the headers/functions/decls | ||
15 | dnl will be put only once into the 'configure' file. It keeps the size of | ||
16 | dnl the 'configure' file down, and avoids redundant output when 'configure' | ||
17 | dnl is run. | ||
18 | dnl The drawback is that the checks cannot be conditionalized. If you write | ||
19 | dnl if some_condition; then gl_CHECK_HEADERS(stdlib.h); fi | ||
20 | dnl inside an AC_DEFUNed function, the gl_CHECK_HEADERS macro call expands to | ||
21 | dnl empty, and the check will be inserted before the body of the AC_DEFUNed | ||
22 | dnl function. | ||
23 | |||
24 | dnl This is like onceonly.m4, except that it uses diversions to named sections | ||
25 | dnl DEFAULTS and INIT_PREPARE in order to check all requested headers at once, | ||
26 | dnl thus reducing the size of 'configure'. Works with autoconf-2.57. The | ||
27 | dnl size reduction is ca. 9%. | ||
28 | |||
29 | dnl Autoconf version 2.57 or newer is recommended. | ||
30 | AC_PREREQ(2.57) | ||
31 | |||
32 | # AC_CHECK_HEADERS_ONCE(HEADER1 HEADER2 ...) is a once-only variant of | ||
33 | # AC_CHECK_HEADERS(HEADER1 HEADER2 ...). | ||
34 | AC_DEFUN([AC_CHECK_HEADERS_ONCE], [ | ||
35 | : | ||
36 | AC_FOREACH([gl_HEADER_NAME], [$1], [ | ||
37 | AC_DEFUN([gl_CHECK_HEADER_]m4_quote(translit(gl_HEADER_NAME, | ||
38 | [./-], [___])), [ | ||
39 | m4_divert_text([INIT_PREPARE], | ||
40 | [gl_header_list="$gl_header_list gl_HEADER_NAME"]) | ||
41 | gl_HEADERS_EXPANSION | ||
42 | AH_TEMPLATE(AS_TR_CPP([HAVE_]m4_defn([gl_HEADER_NAME])), | ||
43 | [Define to 1 if you have the <]m4_defn([gl_HEADER_NAME])[> header file.]) | ||
44 | ]) | ||
45 | AC_REQUIRE([gl_CHECK_HEADER_]m4_quote(translit(gl_HEADER_NAME, | ||
46 | [./-], [___]))) | ||
47 | ]) | ||
48 | ]) | ||
49 | m4_define([gl_HEADERS_EXPANSION], [ | ||
50 | m4_divert_text([DEFAULTS], [gl_header_list=]) | ||
51 | AC_CHECK_HEADERS([$gl_header_list]) | ||
52 | m4_define([gl_HEADERS_EXPANSION], []) | ||
53 | ]) | ||
54 | |||
55 | # AC_CHECK_FUNCS_ONCE(FUNC1 FUNC2 ...) is a once-only variant of | ||
56 | # AC_CHECK_FUNCS(FUNC1 FUNC2 ...). | ||
57 | AC_DEFUN([AC_CHECK_FUNCS_ONCE], [ | ||
58 | : | ||
59 | AC_FOREACH([gl_FUNC_NAME], [$1], [ | ||
60 | AC_DEFUN([gl_CHECK_FUNC_]m4_defn([gl_FUNC_NAME]), [ | ||
61 | m4_divert_text([INIT_PREPARE], | ||
62 | [gl_func_list="$gl_func_list gl_FUNC_NAME"]) | ||
63 | gl_FUNCS_EXPANSION | ||
64 | AH_TEMPLATE(AS_TR_CPP([HAVE_]m4_defn([gl_FUNC_NAME])), | ||
65 | [Define to 1 if you have the `]m4_defn([gl_FUNC_NAME])[' function.]) | ||
66 | ]) | ||
67 | AC_REQUIRE([gl_CHECK_FUNC_]m4_defn([gl_FUNC_NAME])) | ||
68 | ]) | ||
69 | ]) | ||
70 | m4_define([gl_FUNCS_EXPANSION], [ | ||
71 | m4_divert_text([DEFAULTS], [gl_func_list=]) | ||
72 | AC_CHECK_FUNCS([$gl_func_list]) | ||
73 | m4_define([gl_FUNCS_EXPANSION], []) | ||
74 | ]) | ||
75 | |||
76 | # AC_CHECK_DECLS_ONCE(DECL1 DECL2 ...) is a once-only variant of | ||
77 | # AC_CHECK_DECLS(DECL1, DECL2, ...). | ||
78 | AC_DEFUN([AC_CHECK_DECLS_ONCE], [ | ||
79 | : | ||
80 | AC_FOREACH([gl_DECL_NAME], [$1], [ | ||
81 | AC_DEFUN([gl_CHECK_DECL_]m4_defn([gl_DECL_NAME]), [ | ||
82 | AC_CHECK_DECLS(m4_defn([gl_DECL_NAME])) | ||
83 | ]) | ||
84 | AC_REQUIRE([gl_CHECK_DECL_]m4_defn([gl_DECL_NAME])) | ||
85 | ]) | ||
86 | ]) | ||
diff --git a/gl/m4/po.m4 b/gl/m4/po.m4 new file mode 100644 index 00000000..00133ef3 --- /dev/null +++ b/gl/m4/po.m4 | |||
@@ -0,0 +1,428 @@ | |||
1 | # po.m4 serial 13 (gettext-0.15) | ||
2 | dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | dnl | ||
7 | dnl This file can can be used in projects which are not available under | ||
8 | dnl the GNU General Public License or the GNU Library General Public | ||
9 | dnl License but which still want to provide support for the GNU gettext | ||
10 | dnl functionality. | ||
11 | dnl Please note that the actual code of the GNU gettext library is covered | ||
12 | dnl by the GNU Library General Public License, and the rest of the GNU | ||
13 | dnl gettext package package is covered by the GNU General Public License. | ||
14 | dnl They are *not* in the public domain. | ||
15 | |||
16 | dnl Authors: | ||
17 | dnl Ulrich Drepper <drepper@cygnus.com>, 1995-2000. | ||
18 | dnl Bruno Haible <haible@clisp.cons.org>, 2000-2003. | ||
19 | |||
20 | AC_PREREQ(2.50) | ||
21 | |||
22 | dnl Checks for all prerequisites of the po subdirectory. | ||
23 | AC_DEFUN([AM_PO_SUBDIRS], | ||
24 | [ | ||
25 | AC_REQUIRE([AC_PROG_MAKE_SET])dnl | ||
26 | AC_REQUIRE([AC_PROG_INSTALL])dnl | ||
27 | AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake | ||
28 | AC_REQUIRE([AM_NLS])dnl | ||
29 | |||
30 | dnl Perform the following tests also if --disable-nls has been given, | ||
31 | dnl because they are needed for "make dist" to work. | ||
32 | |||
33 | dnl Search for GNU msgfmt in the PATH. | ||
34 | dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. | ||
35 | dnl The second test excludes FreeBSD msgfmt. | ||
36 | AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, | ||
37 | [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && | ||
38 | (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], | ||
39 | :) | ||
40 | AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) | ||
41 | |||
42 | dnl Test whether it is GNU msgfmt >= 0.15. | ||
43 | changequote(,)dnl | ||
44 | case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in | ||
45 | '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; | ||
46 | *) MSGFMT_015=$MSGFMT ;; | ||
47 | esac | ||
48 | changequote([,])dnl | ||
49 | AC_SUBST([MSGFMT_015]) | ||
50 | changequote(,)dnl | ||
51 | case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in | ||
52 | '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; | ||
53 | *) GMSGFMT_015=$GMSGFMT ;; | ||
54 | esac | ||
55 | changequote([,])dnl | ||
56 | AC_SUBST([GMSGFMT_015]) | ||
57 | |||
58 | dnl Search for GNU xgettext 0.12 or newer in the PATH. | ||
59 | dnl The first test excludes Solaris xgettext and early GNU xgettext versions. | ||
60 | dnl The second test excludes FreeBSD xgettext. | ||
61 | AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, | ||
62 | [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && | ||
63 | (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], | ||
64 | :) | ||
65 | dnl Remove leftover from FreeBSD xgettext call. | ||
66 | rm -f messages.po | ||
67 | |||
68 | dnl Test whether it is GNU xgettext >= 0.15. | ||
69 | changequote(,)dnl | ||
70 | case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in | ||
71 | '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; | ||
72 | *) XGETTEXT_015=$XGETTEXT ;; | ||
73 | esac | ||
74 | changequote([,])dnl | ||
75 | AC_SUBST([XGETTEXT_015]) | ||
76 | |||
77 | dnl Search for GNU msgmerge 0.11 or newer in the PATH. | ||
78 | AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, | ||
79 | [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :) | ||
80 | |||
81 | dnl Installation directories. | ||
82 | dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we | ||
83 | dnl have to define it here, so that it can be used in po/Makefile. | ||
84 | test -n "$localedir" || localedir='${datadir}/locale' | ||
85 | AC_SUBST([localedir]) | ||
86 | |||
87 | AC_CONFIG_COMMANDS([po-directories], [[ | ||
88 | for ac_file in $CONFIG_FILES; do | ||
89 | # Support "outfile[:infile[:infile...]]" | ||
90 | case "$ac_file" in | ||
91 | *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; | ||
92 | esac | ||
93 | # PO directories have a Makefile.in generated from Makefile.in.in. | ||
94 | case "$ac_file" in */Makefile.in) | ||
95 | # Adjust a relative srcdir. | ||
96 | ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` | ||
97 | ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" | ||
98 | ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` | ||
99 | # In autoconf-2.13 it is called $ac_given_srcdir. | ||
100 | # In autoconf-2.50 it is called $srcdir. | ||
101 | test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" | ||
102 | case "$ac_given_srcdir" in | ||
103 | .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; | ||
104 | /*) top_srcdir="$ac_given_srcdir" ;; | ||
105 | *) top_srcdir="$ac_dots$ac_given_srcdir" ;; | ||
106 | esac | ||
107 | # Treat a directory as a PO directory if and only if it has a | ||
108 | # POTFILES.in file. This allows packages to have multiple PO | ||
109 | # directories under different names or in different locations. | ||
110 | if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then | ||
111 | rm -f "$ac_dir/POTFILES" | ||
112 | test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" | ||
113 | cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" | ||
114 | POMAKEFILEDEPS="POTFILES.in" | ||
115 | # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend | ||
116 | # on $ac_dir but don't depend on user-specified configuration | ||
117 | # parameters. | ||
118 | if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then | ||
119 | # The LINGUAS file contains the set of available languages. | ||
120 | if test -n "$OBSOLETE_ALL_LINGUAS"; then | ||
121 | test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" | ||
122 | fi | ||
123 | ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` | ||
124 | # Hide the ALL_LINGUAS assigment from automake < 1.5. | ||
125 | eval 'ALL_LINGUAS''=$ALL_LINGUAS_' | ||
126 | POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" | ||
127 | else | ||
128 | # The set of available languages was given in configure.in. | ||
129 | # Hide the ALL_LINGUAS assigment from automake < 1.5. | ||
130 | eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' | ||
131 | fi | ||
132 | # Compute POFILES | ||
133 | # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) | ||
134 | # Compute UPDATEPOFILES | ||
135 | # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) | ||
136 | # Compute DUMMYPOFILES | ||
137 | # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) | ||
138 | # Compute GMOFILES | ||
139 | # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) | ||
140 | case "$ac_given_srcdir" in | ||
141 | .) srcdirpre= ;; | ||
142 | *) srcdirpre='$(srcdir)/' ;; | ||
143 | esac | ||
144 | POFILES= | ||
145 | UPDATEPOFILES= | ||
146 | DUMMYPOFILES= | ||
147 | GMOFILES= | ||
148 | for lang in $ALL_LINGUAS; do | ||
149 | POFILES="$POFILES $srcdirpre$lang.po" | ||
150 | UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" | ||
151 | DUMMYPOFILES="$DUMMYPOFILES $lang.nop" | ||
152 | GMOFILES="$GMOFILES $srcdirpre$lang.gmo" | ||
153 | done | ||
154 | # CATALOGS depends on both $ac_dir and the user's LINGUAS | ||
155 | # environment variable. | ||
156 | INST_LINGUAS= | ||
157 | if test -n "$ALL_LINGUAS"; then | ||
158 | for presentlang in $ALL_LINGUAS; do | ||
159 | useit=no | ||
160 | if test "%UNSET%" != "$LINGUAS"; then | ||
161 | desiredlanguages="$LINGUAS" | ||
162 | else | ||
163 | desiredlanguages="$ALL_LINGUAS" | ||
164 | fi | ||
165 | for desiredlang in $desiredlanguages; do | ||
166 | # Use the presentlang catalog if desiredlang is | ||
167 | # a. equal to presentlang, or | ||
168 | # b. a variant of presentlang (because in this case, | ||
169 | # presentlang can be used as a fallback for messages | ||
170 | # which are not translated in the desiredlang catalog). | ||
171 | case "$desiredlang" in | ||
172 | "$presentlang"*) useit=yes;; | ||
173 | esac | ||
174 | done | ||
175 | if test $useit = yes; then | ||
176 | INST_LINGUAS="$INST_LINGUAS $presentlang" | ||
177 | fi | ||
178 | done | ||
179 | fi | ||
180 | CATALOGS= | ||
181 | if test -n "$INST_LINGUAS"; then | ||
182 | for lang in $INST_LINGUAS; do | ||
183 | CATALOGS="$CATALOGS $lang.gmo" | ||
184 | done | ||
185 | fi | ||
186 | test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" | ||
187 | sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" | ||
188 | for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do | ||
189 | if test -f "$f"; then | ||
190 | case "$f" in | ||
191 | *.orig | *.bak | *~) ;; | ||
192 | *) cat "$f" >> "$ac_dir/Makefile" ;; | ||
193 | esac | ||
194 | fi | ||
195 | done | ||
196 | fi | ||
197 | ;; | ||
198 | esac | ||
199 | done]], | ||
200 | [# Capture the value of obsolete ALL_LINGUAS because we need it to compute | ||
201 | # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it | ||
202 | # from automake < 1.5. | ||
203 | eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' | ||
204 | # Capture the value of LINGUAS because we need it to compute CATALOGS. | ||
205 | LINGUAS="${LINGUAS-%UNSET%}" | ||
206 | ]) | ||
207 | ]) | ||
208 | |||
209 | dnl Postprocesses a Makefile in a directory containing PO files. | ||
210 | AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], | ||
211 | [ | ||
212 | # When this code is run, in config.status, two variables have already been | ||
213 | # set: | ||
214 | # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, | ||
215 | # - LINGUAS is the value of the environment variable LINGUAS at configure | ||
216 | # time. | ||
217 | |||
218 | changequote(,)dnl | ||
219 | # Adjust a relative srcdir. | ||
220 | ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` | ||
221 | ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" | ||
222 | ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` | ||
223 | # In autoconf-2.13 it is called $ac_given_srcdir. | ||
224 | # In autoconf-2.50 it is called $srcdir. | ||
225 | test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" | ||
226 | case "$ac_given_srcdir" in | ||
227 | .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; | ||
228 | /*) top_srcdir="$ac_given_srcdir" ;; | ||
229 | *) top_srcdir="$ac_dots$ac_given_srcdir" ;; | ||
230 | esac | ||
231 | |||
232 | # Find a way to echo strings without interpreting backslash. | ||
233 | if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then | ||
234 | gt_echo='echo' | ||
235 | else | ||
236 | if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then | ||
237 | gt_echo='printf %s\n' | ||
238 | else | ||
239 | echo_func () { | ||
240 | cat <<EOT | ||
241 | $* | ||
242 | EOT | ||
243 | } | ||
244 | gt_echo='echo_func' | ||
245 | fi | ||
246 | fi | ||
247 | |||
248 | # A sed script that extracts the value of VARIABLE from a Makefile. | ||
249 | sed_x_variable=' | ||
250 | # Test if the hold space is empty. | ||
251 | x | ||
252 | s/P/P/ | ||
253 | x | ||
254 | ta | ||
255 | # Yes it was empty. Look if we have the expected variable definition. | ||
256 | /^[ ]*VARIABLE[ ]*=/{ | ||
257 | # Seen the first line of the variable definition. | ||
258 | s/^[ ]*VARIABLE[ ]*=// | ||
259 | ba | ||
260 | } | ||
261 | bd | ||
262 | :a | ||
263 | # Here we are processing a line from the variable definition. | ||
264 | # Remove comment, more precisely replace it with a space. | ||
265 | s/#.*$/ / | ||
266 | # See if the line ends in a backslash. | ||
267 | tb | ||
268 | :b | ||
269 | s/\\$// | ||
270 | # Print the line, without the trailing backslash. | ||
271 | p | ||
272 | tc | ||
273 | # There was no trailing backslash. The end of the variable definition is | ||
274 | # reached. Clear the hold space. | ||
275 | s/^.*$// | ||
276 | x | ||
277 | bd | ||
278 | :c | ||
279 | # A trailing backslash means that the variable definition continues in the | ||
280 | # next line. Put a nonempty string into the hold space to indicate this. | ||
281 | s/^.*$/P/ | ||
282 | x | ||
283 | :d | ||
284 | ' | ||
285 | changequote([,])dnl | ||
286 | |||
287 | # Set POTFILES to the value of the Makefile variable POTFILES. | ||
288 | sed_x_POTFILES=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/POTFILES/g'` | ||
289 | POTFILES=`sed -n -e "$sed_x_POTFILES" < "$ac_file"` | ||
290 | # Compute POTFILES_DEPS as | ||
291 | # $(foreach file, $(POTFILES), $(top_srcdir)/$(file)) | ||
292 | POTFILES_DEPS= | ||
293 | for file in $POTFILES; do | ||
294 | POTFILES_DEPS="$POTFILES_DEPS "'$(top_srcdir)/'"$file" | ||
295 | done | ||
296 | POMAKEFILEDEPS="" | ||
297 | |||
298 | if test -n "$OBSOLETE_ALL_LINGUAS"; then | ||
299 | test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" | ||
300 | fi | ||
301 | if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then | ||
302 | # The LINGUAS file contains the set of available languages. | ||
303 | ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` | ||
304 | POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" | ||
305 | else | ||
306 | # Set ALL_LINGUAS to the value of the Makefile variable LINGUAS. | ||
307 | sed_x_LINGUAS=`$gt_echo "$sed_x_variable" | sed -e '/^ *#/d' -e 's/VARIABLE/LINGUAS/g'` | ||
308 | ALL_LINGUAS_=`sed -n -e "$sed_x_LINGUAS" < "$ac_file"` | ||
309 | fi | ||
310 | # Hide the ALL_LINGUAS assigment from automake < 1.5. | ||
311 | eval 'ALL_LINGUAS''=$ALL_LINGUAS_' | ||
312 | # Compute POFILES | ||
313 | # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) | ||
314 | # Compute UPDATEPOFILES | ||
315 | # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) | ||
316 | # Compute DUMMYPOFILES | ||
317 | # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) | ||
318 | # Compute GMOFILES | ||
319 | # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) | ||
320 | # Compute PROPERTIESFILES | ||
321 | # as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).properties) | ||
322 | # Compute CLASSFILES | ||
323 | # as $(foreach lang, $(ALL_LINGUAS), $(top_srcdir)/$(DOMAIN)_$(lang).class) | ||
324 | # Compute QMFILES | ||
325 | # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).qm) | ||
326 | # Compute MSGFILES | ||
327 | # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang)).msg) | ||
328 | # Compute RESOURCESDLLFILES | ||
329 | # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(frob $(lang))/$(DOMAIN).resources.dll) | ||
330 | case "$ac_given_srcdir" in | ||
331 | .) srcdirpre= ;; | ||
332 | *) srcdirpre='$(srcdir)/' ;; | ||
333 | esac | ||
334 | POFILES= | ||
335 | UPDATEPOFILES= | ||
336 | DUMMYPOFILES= | ||
337 | GMOFILES= | ||
338 | PROPERTIESFILES= | ||
339 | CLASSFILES= | ||
340 | QMFILES= | ||
341 | MSGFILES= | ||
342 | RESOURCESDLLFILES= | ||
343 | for lang in $ALL_LINGUAS; do | ||
344 | POFILES="$POFILES $srcdirpre$lang.po" | ||
345 | UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" | ||
346 | DUMMYPOFILES="$DUMMYPOFILES $lang.nop" | ||
347 | GMOFILES="$GMOFILES $srcdirpre$lang.gmo" | ||
348 | PROPERTIESFILES="$PROPERTIESFILES \$(top_srcdir)/\$(DOMAIN)_$lang.properties" | ||
349 | CLASSFILES="$CLASSFILES \$(top_srcdir)/\$(DOMAIN)_$lang.class" | ||
350 | QMFILES="$QMFILES $srcdirpre$lang.qm" | ||
351 | frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` | ||
352 | MSGFILES="$MSGFILES $srcdirpre$frobbedlang.msg" | ||
353 | frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` | ||
354 | RESOURCESDLLFILES="$RESOURCESDLLFILES $srcdirpre$frobbedlang/\$(DOMAIN).resources.dll" | ||
355 | done | ||
356 | # CATALOGS depends on both $ac_dir and the user's LINGUAS | ||
357 | # environment variable. | ||
358 | INST_LINGUAS= | ||
359 | if test -n "$ALL_LINGUAS"; then | ||
360 | for presentlang in $ALL_LINGUAS; do | ||
361 | useit=no | ||
362 | if test "%UNSET%" != "$LINGUAS"; then | ||
363 | desiredlanguages="$LINGUAS" | ||
364 | else | ||
365 | desiredlanguages="$ALL_LINGUAS" | ||
366 | fi | ||
367 | for desiredlang in $desiredlanguages; do | ||
368 | # Use the presentlang catalog if desiredlang is | ||
369 | # a. equal to presentlang, or | ||
370 | # b. a variant of presentlang (because in this case, | ||
371 | # presentlang can be used as a fallback for messages | ||
372 | # which are not translated in the desiredlang catalog). | ||
373 | case "$desiredlang" in | ||
374 | "$presentlang"*) useit=yes;; | ||
375 | esac | ||
376 | done | ||
377 | if test $useit = yes; then | ||
378 | INST_LINGUAS="$INST_LINGUAS $presentlang" | ||
379 | fi | ||
380 | done | ||
381 | fi | ||
382 | CATALOGS= | ||
383 | JAVACATALOGS= | ||
384 | QTCATALOGS= | ||
385 | TCLCATALOGS= | ||
386 | CSHARPCATALOGS= | ||
387 | if test -n "$INST_LINGUAS"; then | ||
388 | for lang in $INST_LINGUAS; do | ||
389 | CATALOGS="$CATALOGS $lang.gmo" | ||
390 | JAVACATALOGS="$JAVACATALOGS \$(DOMAIN)_$lang.properties" | ||
391 | QTCATALOGS="$QTCATALOGS $lang.qm" | ||
392 | frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` | ||
393 | TCLCATALOGS="$TCLCATALOGS $frobbedlang.msg" | ||
394 | frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` | ||
395 | CSHARPCATALOGS="$CSHARPCATALOGS $frobbedlang/\$(DOMAIN).resources.dll" | ||
396 | done | ||
397 | fi | ||
398 | |||
399 | sed -e "s|@POTFILES_DEPS@|$POTFILES_DEPS|g" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@PROPERTIESFILES@|$PROPERTIESFILES|g" -e "s|@CLASSFILES@|$CLASSFILES|g" -e "s|@QMFILES@|$QMFILES|g" -e "s|@MSGFILES@|$MSGFILES|g" -e "s|@RESOURCESDLLFILES@|$RESOURCESDLLFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@JAVACATALOGS@|$JAVACATALOGS|g" -e "s|@QTCATALOGS@|$QTCATALOGS|g" -e "s|@TCLCATALOGS@|$TCLCATALOGS|g" -e "s|@CSHARPCATALOGS@|$CSHARPCATALOGS|g" -e 's,^#distdir:,distdir:,' < "$ac_file" > "$ac_file.tmp" | ||
400 | if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then | ||
401 | # Add dependencies that cannot be formulated as a simple suffix rule. | ||
402 | for lang in $ALL_LINGUAS; do | ||
403 | frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` | ||
404 | cat >> "$ac_file.tmp" <<EOF | ||
405 | $frobbedlang.msg: $lang.po | ||
406 | @echo "\$(MSGFMT) -c --tcl -d \$(srcdir) -l $lang $srcdirpre$lang.po"; \ | ||
407 | \$(MSGFMT) -c --tcl -d "\$(srcdir)" -l $lang $srcdirpre$lang.po || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; } | ||
408 | EOF | ||
409 | done | ||
410 | fi | ||
411 | if grep -l '@CSHARPCATALOGS@' "$ac_file" > /dev/null; then | ||
412 | # Add dependencies that cannot be formulated as a simple suffix rule. | ||
413 | for lang in $ALL_LINGUAS; do | ||
414 | frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` | ||
415 | cat >> "$ac_file.tmp" <<EOF | ||
416 | $frobbedlang/\$(DOMAIN).resources.dll: $lang.po | ||
417 | @echo "\$(MSGFMT) -c --csharp -d \$(srcdir) -l $lang $srcdirpre$lang.po -r \$(DOMAIN)"; \ | ||
418 | \$(MSGFMT) -c --csharp -d "\$(srcdir)" -l $lang $srcdirpre$lang.po -r "\$(DOMAIN)" || { rm -f "\$(srcdir)/$frobbedlang.msg"; exit 1; } | ||
419 | EOF | ||
420 | done | ||
421 | fi | ||
422 | if test -n "$POMAKEFILEDEPS"; then | ||
423 | cat >> "$ac_file.tmp" <<EOF | ||
424 | Makefile: $POMAKEFILEDEPS | ||
425 | EOF | ||
426 | fi | ||
427 | mv "$ac_file.tmp" "$ac_file" | ||
428 | ]) | ||
diff --git a/gl/m4/printf-posix.m4 b/gl/m4/printf-posix.m4 new file mode 100644 index 00000000..af10170a --- /dev/null +++ b/gl/m4/printf-posix.m4 | |||
@@ -0,0 +1,44 @@ | |||
1 | # printf-posix.m4 serial 2 (gettext-0.13.1) | ||
2 | dnl Copyright (C) 2003 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | dnl Test whether the printf() function supports POSIX/XSI format strings with | ||
9 | dnl positions. | ||
10 | |||
11 | AC_DEFUN([gt_PRINTF_POSIX], | ||
12 | [ | ||
13 | AC_REQUIRE([AC_PROG_CC]) | ||
14 | AC_CACHE_CHECK([whether printf() supports POSIX/XSI format strings], | ||
15 | gt_cv_func_printf_posix, | ||
16 | [ | ||
17 | AC_TRY_RUN([ | ||
18 | #include <stdio.h> | ||
19 | #include <string.h> | ||
20 | /* The string "%2$d %1$d", with dollar characters protected from the shell's | ||
21 | dollar expansion (possibly an autoconf bug). */ | ||
22 | static char format[] = { '%', '2', '$', 'd', ' ', '%', '1', '$', 'd', '\0' }; | ||
23 | static char buf[100]; | ||
24 | int main () | ||
25 | { | ||
26 | sprintf (buf, format, 33, 55); | ||
27 | return (strcmp (buf, "55 33") != 0); | ||
28 | }], gt_cv_func_printf_posix=yes, gt_cv_func_printf_posix=no, | ||
29 | [ | ||
30 | AC_EGREP_CPP(notposix, [ | ||
31 | #if defined __NetBSD__ || defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ | ||
32 | notposix | ||
33 | #endif | ||
34 | ], gt_cv_func_printf_posix="guessing no", | ||
35 | gt_cv_func_printf_posix="guessing yes") | ||
36 | ]) | ||
37 | ]) | ||
38 | case $gt_cv_func_printf_posix in | ||
39 | *yes) | ||
40 | AC_DEFINE(HAVE_POSIX_PRINTF, 1, | ||
41 | [Define if your printf() function supports format strings with positions.]) | ||
42 | ;; | ||
43 | esac | ||
44 | ]) | ||
diff --git a/gl/m4/progtest.m4 b/gl/m4/progtest.m4 new file mode 100644 index 00000000..a56365cd --- /dev/null +++ b/gl/m4/progtest.m4 | |||
@@ -0,0 +1,92 @@ | |||
1 | # progtest.m4 serial 4 (gettext-0.14.2) | ||
2 | dnl Copyright (C) 1996-2003, 2005 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | dnl | ||
7 | dnl This file can can be used in projects which are not available under | ||
8 | dnl the GNU General Public License or the GNU Library General Public | ||
9 | dnl License but which still want to provide support for the GNU gettext | ||
10 | dnl functionality. | ||
11 | dnl Please note that the actual code of the GNU gettext library is covered | ||
12 | dnl by the GNU Library General Public License, and the rest of the GNU | ||
13 | dnl gettext package package is covered by the GNU General Public License. | ||
14 | dnl They are *not* in the public domain. | ||
15 | |||
16 | dnl Authors: | ||
17 | dnl Ulrich Drepper <drepper@cygnus.com>, 1996. | ||
18 | |||
19 | AC_PREREQ(2.50) | ||
20 | |||
21 | # Search path for a program which passes the given test. | ||
22 | |||
23 | dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, | ||
24 | dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) | ||
25 | AC_DEFUN([AM_PATH_PROG_WITH_TEST], | ||
26 | [ | ||
27 | # Prepare PATH_SEPARATOR. | ||
28 | # The user is always right. | ||
29 | if test "${PATH_SEPARATOR+set}" != set; then | ||
30 | echo "#! /bin/sh" >conf$$.sh | ||
31 | echo "exit 0" >>conf$$.sh | ||
32 | chmod +x conf$$.sh | ||
33 | if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then | ||
34 | PATH_SEPARATOR=';' | ||
35 | else | ||
36 | PATH_SEPARATOR=: | ||
37 | fi | ||
38 | rm -f conf$$.sh | ||
39 | fi | ||
40 | |||
41 | # Find out how to test for executable files. Don't use a zero-byte file, | ||
42 | # as systems may use methods other than mode bits to determine executability. | ||
43 | cat >conf$$.file <<_ASEOF | ||
44 | #! /bin/sh | ||
45 | exit 0 | ||
46 | _ASEOF | ||
47 | chmod +x conf$$.file | ||
48 | if test -x conf$$.file >/dev/null 2>&1; then | ||
49 | ac_executable_p="test -x" | ||
50 | else | ||
51 | ac_executable_p="test -f" | ||
52 | fi | ||
53 | rm -f conf$$.file | ||
54 | |||
55 | # Extract the first word of "$2", so it can be a program name with args. | ||
56 | set dummy $2; ac_word=[$]2 | ||
57 | AC_MSG_CHECKING([for $ac_word]) | ||
58 | AC_CACHE_VAL(ac_cv_path_$1, | ||
59 | [case "[$]$1" in | ||
60 | [[\\/]]* | ?:[[\\/]]*) | ||
61 | ac_cv_path_$1="[$]$1" # Let the user override the test with a path. | ||
62 | ;; | ||
63 | *) | ||
64 | ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR | ||
65 | for ac_dir in ifelse([$5], , $PATH, [$5]); do | ||
66 | IFS="$ac_save_IFS" | ||
67 | test -z "$ac_dir" && ac_dir=. | ||
68 | for ac_exec_ext in '' $ac_executable_extensions; do | ||
69 | if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then | ||
70 | echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD | ||
71 | if [$3]; then | ||
72 | ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" | ||
73 | break 2 | ||
74 | fi | ||
75 | fi | ||
76 | done | ||
77 | done | ||
78 | IFS="$ac_save_IFS" | ||
79 | dnl If no 4th arg is given, leave the cache variable unset, | ||
80 | dnl so AC_PATH_PROGS will keep looking. | ||
81 | ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" | ||
82 | ])dnl | ||
83 | ;; | ||
84 | esac])dnl | ||
85 | $1="$ac_cv_path_$1" | ||
86 | if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then | ||
87 | AC_MSG_RESULT([$]$1) | ||
88 | else | ||
89 | AC_MSG_RESULT(no) | ||
90 | fi | ||
91 | AC_SUBST($1)dnl | ||
92 | ]) | ||
diff --git a/gl/m4/regex.m4 b/gl/m4/regex.m4 new file mode 100644 index 00000000..25da645e --- /dev/null +++ b/gl/m4/regex.m4 | |||
@@ -0,0 +1,198 @@ | |||
1 | #serial 42 | ||
2 | |||
3 | # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, | ||
4 | # 2006, 2007 Free Software Foundation, Inc. | ||
5 | # | ||
6 | # This file is free software; the Free Software Foundation | ||
7 | # gives unlimited permission to copy and/or distribute it, | ||
8 | # with or without modifications, as long as this notice is preserved. | ||
9 | |||
10 | dnl Initially derived from code in GNU grep. | ||
11 | dnl Mostly written by Jim Meyering. | ||
12 | |||
13 | AC_PREREQ([2.50]) | ||
14 | |||
15 | AC_DEFUN([gl_REGEX], | ||
16 | [ | ||
17 | AC_CHECK_HEADERS_ONCE([locale.h]) | ||
18 | |||
19 | AC_ARG_WITH([included-regex], | ||
20 | [AC_HELP_STRING([--without-included-regex], | ||
21 | [don't compile regex; this is the default on | ||
22 | systems with recent-enough versions of the GNU C | ||
23 | Library (use with caution on other systems)])]) | ||
24 | |||
25 | case $with_included_regex in #( | ||
26 | yes|no) ac_use_included_regex=$with_included_regex | ||
27 | ;; | ||
28 | '') | ||
29 | # If the system regex support is good enough that it passes the | ||
30 | # following run test, then default to *not* using the included regex.c. | ||
31 | # If cross compiling, assume the test would fail and use the included | ||
32 | # regex.c. The first failing regular expression is from `Spencer ere | ||
33 | # test #75' in grep-2.3. | ||
34 | AC_CACHE_CHECK([for working re_compile_pattern], | ||
35 | [gl_cv_func_re_compile_pattern_working], | ||
36 | [AC_RUN_IFELSE( | ||
37 | [AC_LANG_PROGRAM( | ||
38 | [AC_INCLUDES_DEFAULT | ||
39 | #if HAVE_LOCALE_H | ||
40 | #include <locale.h> | ||
41 | #endif | ||
42 | #include <limits.h> | ||
43 | #include <regex.h> | ||
44 | ], | ||
45 | [[static struct re_pattern_buffer regex; | ||
46 | unsigned char folded_chars[UCHAR_MAX + 1]; | ||
47 | int i; | ||
48 | const char *s; | ||
49 | struct re_registers regs; | ||
50 | |||
51 | #if HAVE_LOCALE_H | ||
52 | /* http://sourceware.org/ml/libc-hacker/2006-09/msg00008.html | ||
53 | This test needs valgrind to catch the bug on Debian | ||
54 | GNU/Linux 3.1 x86, but it might catch the bug better | ||
55 | on other platforms and it shouldn't hurt to try the | ||
56 | test here. */ | ||
57 | if (setlocale (LC_ALL, "en_US.UTF-8")) | ||
58 | { | ||
59 | static char const pat[] = "insert into"; | ||
60 | static char const data[] = | ||
61 | "\xFF\0\x12\xA2\xAA\xC4\xB1,K\x12\xC4\xB1*\xACK"; | ||
62 | re_set_syntax (RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE | ||
63 | | RE_ICASE); | ||
64 | memset (®ex, 0, sizeof regex); | ||
65 | s = re_compile_pattern (pat, sizeof pat - 1, ®ex); | ||
66 | if (s) | ||
67 | return 1; | ||
68 | if (re_search (®ex, data, sizeof data - 1, | ||
69 | 0, sizeof data - 1, ®s) | ||
70 | != -1) | ||
71 | return 1; | ||
72 | if (! setlocale (LC_ALL, "C")) | ||
73 | return 1; | ||
74 | } | ||
75 | #endif | ||
76 | |||
77 | re_set_syntax (RE_SYNTAX_POSIX_EGREP); | ||
78 | memset (®ex, 0, sizeof (regex)); | ||
79 | for (i = 0; i <= UCHAR_MAX; i++) | ||
80 | folded_chars[i] = i; | ||
81 | regex.translate = folded_chars; | ||
82 | s = re_compile_pattern ("a[[:@:>@:]]b\n", 11, ®ex); | ||
83 | /* This should fail with _Invalid character class name_ error. */ | ||
84 | if (!s) | ||
85 | exit (1); | ||
86 | |||
87 | /* This should succeed, but does not for e.g. glibc-2.1.3. */ | ||
88 | memset (®ex, 0, sizeof (regex)); | ||
89 | s = re_compile_pattern ("{1", 2, ®ex); | ||
90 | |||
91 | if (s) | ||
92 | exit (1); | ||
93 | |||
94 | /* The following example is derived from a problem report | ||
95 | against gawk from Jorge Stolfi <stolfi@ic.unicamp.br>. */ | ||
96 | memset (®ex, 0, sizeof (regex)); | ||
97 | s = re_compile_pattern ("[an\371]*n", 7, ®ex); | ||
98 | if (s) | ||
99 | exit (1); | ||
100 | |||
101 | /* This should match, but does not for e.g. glibc-2.2.1. */ | ||
102 | if (re_match (®ex, "an", 2, 0, ®s) != 2) | ||
103 | exit (1); | ||
104 | |||
105 | memset (®ex, 0, sizeof (regex)); | ||
106 | s = re_compile_pattern ("x", 1, ®ex); | ||
107 | if (s) | ||
108 | exit (1); | ||
109 | |||
110 | /* The version of regex.c in e.g. GNU libc-2.2.93 did not | ||
111 | work with a negative RANGE argument. */ | ||
112 | if (re_search (®ex, "wxy", 3, 2, -2, ®s) != 1) | ||
113 | exit (1); | ||
114 | |||
115 | /* The version of regex.c in older versions of gnulib | ||
116 | ignored RE_ICASE. Detect that problem too. */ | ||
117 | memset (®ex, 0, sizeof (regex)); | ||
118 | re_set_syntax (RE_SYNTAX_EMACS | RE_ICASE); | ||
119 | s = re_compile_pattern ("x", 1, ®ex); | ||
120 | if (s) | ||
121 | exit (1); | ||
122 | |||
123 | if (re_search (®ex, "WXY", 3, 0, 3, ®s) < 0) | ||
124 | exit (1); | ||
125 | |||
126 | /* REG_STARTEND was added to glibc on 2004-01-15. | ||
127 | Reject older versions. */ | ||
128 | if (! REG_STARTEND) | ||
129 | exit (1); | ||
130 | |||
131 | /* Reject hosts whose regoff_t values are too narrow. | ||
132 | These include glibc 2.3.5 on hosts with 64-bit ptrdiff_t | ||
133 | and 32-bit int. */ | ||
134 | if (sizeof (regoff_t) < sizeof (ptrdiff_t) | ||
135 | || sizeof (regoff_t) < sizeof (ssize_t)) | ||
136 | exit (1); | ||
137 | |||
138 | exit (0);]])], | ||
139 | [gl_cv_func_re_compile_pattern_working=yes], | ||
140 | [gl_cv_func_re_compile_pattern_working=no], | ||
141 | dnl When crosscompiling, assume it is not working. | ||
142 | [gl_cv_func_re_compile_pattern_working=no])]) | ||
143 | case $gl_cv_func_re_compile_pattern_working in #( | ||
144 | yes) ac_use_included_regex=no;; #( | ||
145 | no) ac_use_included_regex=yes;; | ||
146 | esac | ||
147 | ;; | ||
148 | *) AC_MSG_ERROR([Invalid value for --with-included-regex: $with_included_regex]) | ||
149 | ;; | ||
150 | esac | ||
151 | |||
152 | if test $ac_use_included_regex = yes; then | ||
153 | AC_DEFINE([_REGEX_LARGE_OFFSETS], 1, | ||
154 | [Define if you want regoff_t to be at least as wide POSIX requires.]) | ||
155 | AC_DEFINE([re_syntax_options], [rpl_re_syntax_options], | ||
156 | [Define to rpl_re_syntax_options if the replacement should be used.]) | ||
157 | AC_DEFINE([re_set_syntax], [rpl_re_set_syntax], | ||
158 | [Define to rpl_re_set_syntax if the replacement should be used.]) | ||
159 | AC_DEFINE([re_compile_pattern], [rpl_re_compile_pattern], | ||
160 | [Define to rpl_re_compile_pattern if the replacement should be used.]) | ||
161 | AC_DEFINE([re_compile_fastmap], [rpl_re_compile_fastmap], | ||
162 | [Define to rpl_re_compile_fastmap if the replacement should be used.]) | ||
163 | AC_DEFINE([re_search], [rpl_re_search], | ||
164 | [Define to rpl_re_search if the replacement should be used.]) | ||
165 | AC_DEFINE([re_search_2], [rpl_re_search_2], | ||
166 | [Define to rpl_re_search_2 if the replacement should be used.]) | ||
167 | AC_DEFINE([re_match], [rpl_re_match], | ||
168 | [Define to rpl_re_match if the replacement should be used.]) | ||
169 | AC_DEFINE([re_match_2], [rpl_re_match_2], | ||
170 | [Define to rpl_re_match_2 if the replacement should be used.]) | ||
171 | AC_DEFINE([re_set_registers], [rpl_re_set_registers], | ||
172 | [Define to rpl_re_set_registers if the replacement should be used.]) | ||
173 | AC_DEFINE([re_comp], [rpl_re_comp], | ||
174 | [Define to rpl_re_comp if the replacement should be used.]) | ||
175 | AC_DEFINE([re_exec], [rpl_re_exec], | ||
176 | [Define to rpl_re_exec if the replacement should be used.]) | ||
177 | AC_DEFINE([regcomp], [rpl_regcomp], | ||
178 | [Define to rpl_regcomp if the replacement should be used.]) | ||
179 | AC_DEFINE([regexec], [rpl_regexec], | ||
180 | [Define to rpl_regexec if the replacement should be used.]) | ||
181 | AC_DEFINE([regerror], [rpl_regerror], | ||
182 | [Define to rpl_regerror if the replacement should be used.]) | ||
183 | AC_DEFINE([regfree], [rpl_regfree], | ||
184 | [Define to rpl_regfree if the replacement should be used.]) | ||
185 | AC_LIBOBJ([regex]) | ||
186 | gl_PREREQ_REGEX | ||
187 | fi | ||
188 | ]) | ||
189 | |||
190 | # Prerequisites of lib/regex.c and lib/regex_internal.c. | ||
191 | AC_DEFUN([gl_PREREQ_REGEX], | ||
192 | [ | ||
193 | AC_REQUIRE([AC_GNU_SOURCE]) | ||
194 | AC_REQUIRE([AC_C_RESTRICT]) | ||
195 | AC_REQUIRE([AM_LANGINFO_CODESET]) | ||
196 | AC_CHECK_FUNCS_ONCE([iswctype mbrtowc mempcpy wcrtomb wcscoll]) | ||
197 | AC_CHECK_DECLS([isblank], [], [], [#include <ctype.h>]) | ||
198 | ]) | ||
diff --git a/gl/m4/safe-read.m4 b/gl/m4/safe-read.m4 new file mode 100644 index 00000000..7a89d0a6 --- /dev/null +++ b/gl/m4/safe-read.m4 | |||
@@ -0,0 +1,18 @@ | |||
1 | # safe-read.m4 serial 5 | ||
2 | dnl Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_SAFE_READ], | ||
8 | [ | ||
9 | AC_LIBOBJ([safe-read]) | ||
10 | |||
11 | gl_PREREQ_SAFE_READ | ||
12 | ]) | ||
13 | |||
14 | # Prerequisites of lib/safe-read.c. | ||
15 | AC_DEFUN([gl_PREREQ_SAFE_READ], | ||
16 | [ | ||
17 | AC_REQUIRE([gt_TYPE_SSIZE_T]) | ||
18 | ]) | ||
diff --git a/gl/m4/safe-write.m4 b/gl/m4/safe-write.m4 new file mode 100644 index 00000000..db119ffa --- /dev/null +++ b/gl/m4/safe-write.m4 | |||
@@ -0,0 +1,18 @@ | |||
1 | # safe-write.m4 serial 3 | ||
2 | dnl Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_SAFE_WRITE], | ||
8 | [ | ||
9 | AC_LIBOBJ([safe-write]) | ||
10 | |||
11 | gl_PREREQ_SAFE_WRITE | ||
12 | ]) | ||
13 | |||
14 | # Prerequisites of lib/safe-write.c. | ||
15 | AC_DEFUN([gl_PREREQ_SAFE_WRITE], | ||
16 | [ | ||
17 | gl_PREREQ_SAFE_READ | ||
18 | ]) | ||
diff --git a/gl/m4/size_max.m4 b/gl/m4/size_max.m4 new file mode 100644 index 00000000..6cb48689 --- /dev/null +++ b/gl/m4/size_max.m4 | |||
@@ -0,0 +1,68 @@ | |||
1 | # size_max.m4 serial 6 | ||
2 | dnl Copyright (C) 2003, 2005-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | |||
9 | AC_DEFUN([gl_SIZE_MAX], | ||
10 | [ | ||
11 | AC_CHECK_HEADERS(stdint.h) | ||
12 | dnl First test whether the system already has SIZE_MAX. | ||
13 | AC_MSG_CHECKING([for SIZE_MAX]) | ||
14 | AC_CACHE_VAL([gl_cv_size_max], [ | ||
15 | gl_cv_size_max= | ||
16 | AC_EGREP_CPP([Found it], [ | ||
17 | #include <limits.h> | ||
18 | #if HAVE_STDINT_H | ||
19 | #include <stdint.h> | ||
20 | #endif | ||
21 | #ifdef SIZE_MAX | ||
22 | Found it | ||
23 | #endif | ||
24 | ], gl_cv_size_max=yes) | ||
25 | if test -z "$gl_cv_size_max"; then | ||
26 | dnl Define it ourselves. Here we assume that the type 'size_t' is not wider | ||
27 | dnl than the type 'unsigned long'. Try hard to find a definition that can | ||
28 | dnl be used in a preprocessor #if, i.e. doesn't contain a cast. | ||
29 | AC_COMPUTE_INT([size_t_bits_minus_1], [sizeof (size_t) * CHAR_BIT - 1], | ||
30 | [#include <stddef.h> | ||
31 | #include <limits.h>], size_t_bits_minus_1=) | ||
32 | AC_COMPUTE_INT([fits_in_uint], [sizeof (size_t) <= sizeof (unsigned int)], | ||
33 | [#include <stddef.h>], fits_in_uint=) | ||
34 | if test -n "$size_t_bits_minus_1" && test -n "$fits_in_uint"; then | ||
35 | if test $fits_in_uint = 1; then | ||
36 | dnl Even though SIZE_MAX fits in an unsigned int, it must be of type | ||
37 | dnl 'unsigned long' if the type 'size_t' is the same as 'unsigned long'. | ||
38 | AC_TRY_COMPILE([#include <stddef.h> | ||
39 | extern size_t foo; | ||
40 | extern unsigned long foo; | ||
41 | ], [], fits_in_uint=0) | ||
42 | fi | ||
43 | dnl We cannot use 'expr' to simplify this expression, because 'expr' | ||
44 | dnl works only with 'long' integers in the host environment, while we | ||
45 | dnl might be cross-compiling from a 32-bit platform to a 64-bit platform. | ||
46 | if test $fits_in_uint = 1; then | ||
47 | gl_cv_size_max="(((1U << $size_t_bits_minus_1) - 1) * 2 + 1)" | ||
48 | else | ||
49 | gl_cv_size_max="(((1UL << $size_t_bits_minus_1) - 1) * 2 + 1)" | ||
50 | fi | ||
51 | else | ||
52 | dnl Shouldn't happen, but who knows... | ||
53 | gl_cv_size_max='((size_t)~(size_t)0)' | ||
54 | fi | ||
55 | fi | ||
56 | ]) | ||
57 | AC_MSG_RESULT([$gl_cv_size_max]) | ||
58 | if test "$gl_cv_size_max" != yes; then | ||
59 | AC_DEFINE_UNQUOTED([SIZE_MAX], [$gl_cv_size_max], | ||
60 | [Define as the maximum value of type 'size_t', if the system doesn't define it.]) | ||
61 | fi | ||
62 | ]) | ||
63 | |||
64 | dnl Autoconf >= 2.61 has AC_COMPUTE_INT built-in. | ||
65 | dnl Remove this when we can assume autoconf >= 2.61. | ||
66 | m4_ifdef([AC_COMPUTE_INT], [], [ | ||
67 | AC_DEFUN([AC_COMPUTE_INT], [_AC_COMPUTE_INT([$2],[$1],[$3],[$4])]) | ||
68 | ]) | ||
diff --git a/gl/m4/snprintf.m4 b/gl/m4/snprintf.m4 new file mode 100644 index 00000000..432e0375 --- /dev/null +++ b/gl/m4/snprintf.m4 | |||
@@ -0,0 +1,15 @@ | |||
1 | # snprintf.m4 serial 2 | ||
2 | dnl Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FUNC_SNPRINTF], | ||
8 | [ | ||
9 | AC_REPLACE_FUNCS(snprintf) | ||
10 | AC_CHECK_DECLS_ONCE(snprintf) | ||
11 | gl_PREREQ_SNPRINTF | ||
12 | ]) | ||
13 | |||
14 | # Prerequisites of lib/snprintf.c. | ||
15 | AC_DEFUN([gl_PREREQ_SNPRINTF], [:]) | ||
diff --git a/gl/m4/socklen.m4 b/gl/m4/socklen.m4 new file mode 100644 index 00000000..5e3765a6 --- /dev/null +++ b/gl/m4/socklen.m4 | |||
@@ -0,0 +1,52 @@ | |||
1 | # socklen.m4 serial 4 | ||
2 | dnl Copyright (C) 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Albert Chin, Windows fixes from Simon Josefsson. | ||
8 | |||
9 | dnl Check for socklen_t: historically on BSD it is an int, and in | ||
10 | dnl POSIX 1g it is a type of its own, but some platforms use different | ||
11 | dnl types for the argument to getsockopt, getpeername, etc. So we | ||
12 | dnl have to test to find something that will work. | ||
13 | |||
14 | dnl On mingw32, socklen_t is in ws2tcpip.h ('int'), so we try to find | ||
15 | dnl it there first. That file is included by gnulib's socket_.h, which | ||
16 | dnl all users of this module should include. Cygwin must not include | ||
17 | dnl ws2tcpip.h. | ||
18 | AC_DEFUN([gl_TYPE_SOCKLEN_T], | ||
19 | [AC_REQUIRE([gl_HEADER_SYS_SOCKET])dnl | ||
20 | AC_CHECK_TYPE([socklen_t], , | ||
21 | [AC_MSG_CHECKING([for socklen_t equivalent]) | ||
22 | AC_CACHE_VAL([gl_cv_gl_cv_socklen_t_equiv], | ||
23 | [# Systems have either "struct sockaddr *" or | ||
24 | # "void *" as the second argument to getpeername | ||
25 | gl_cv_socklen_t_equiv= | ||
26 | for arg2 in "struct sockaddr" void; do | ||
27 | for t in int size_t "unsigned int" "long int" "unsigned long int"; do | ||
28 | AC_TRY_COMPILE( | ||
29 | [#include <sys/types.h> | ||
30 | #include <sys/socket.h> | ||
31 | |||
32 | int getpeername (int, $arg2 *, $t *);], | ||
33 | [$t len; | ||
34 | getpeername (0, 0, &len);], | ||
35 | [gl_cv_socklen_t_equiv="$t"]) | ||
36 | test "$gl_cv_socklen_t_equiv" != "" && break | ||
37 | done | ||
38 | test "$gl_cv_socklen_t_equiv" != "" && break | ||
39 | done | ||
40 | ]) | ||
41 | if test "$gl_cv_socklen_t_equiv" = ""; then | ||
42 | AC_MSG_ERROR([Cannot find a type to use in place of socklen_t]) | ||
43 | fi | ||
44 | AC_MSG_RESULT([$gl_cv_socklen_t_equiv]) | ||
45 | AC_DEFINE_UNQUOTED([socklen_t], [$gl_cv_socklen_t_equiv], | ||
46 | [type to use in place of socklen_t if not defined])], | ||
47 | [#include <sys/types.h> | ||
48 | #if HAVE_SYS_SOCKET_H | ||
49 | # include <sys/socket.h> | ||
50 | #elif HAVE_WS2TCPIP_H | ||
51 | # include <ws2tcpip.h> | ||
52 | #endif])]) | ||
diff --git a/gl/m4/sockpfaf.m4 b/gl/m4/sockpfaf.m4 new file mode 100644 index 00000000..25d9755c --- /dev/null +++ b/gl/m4/sockpfaf.m4 | |||
@@ -0,0 +1,58 @@ | |||
1 | # sockpfaf.m4 serial 5 | ||
2 | dnl Copyright (C) 2004, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl Test for some common socket protocol families (PF_INET, PF_INET6, ...) | ||
8 | dnl and some common address families (AF_INET, AF_INET6, ...). | ||
9 | dnl This test assumes that a system supports an address family if and only if | ||
10 | dnl it supports the corresponding protocol family. | ||
11 | |||
12 | dnl From Bruno Haible. | ||
13 | |||
14 | AC_DEFUN([gl_SOCKET_FAMILIES], | ||
15 | [ | ||
16 | AC_REQUIRE([gl_HEADER_SYS_SOCKET]) | ||
17 | AC_CHECK_HEADERS_ONCE([netinet/in.h]) | ||
18 | |||
19 | AC_MSG_CHECKING(for IPv4 sockets) | ||
20 | AC_CACHE_VAL(gl_cv_socket_ipv4, | ||
21 | [AC_TRY_COMPILE([#include <sys/types.h> | ||
22 | #ifdef HAVE_SYS_SOCKET_H | ||
23 | #include <sys/socket.h> | ||
24 | #endif | ||
25 | #ifdef HAVE_NETINET_IN_H | ||
26 | #include <netinet/in.h> | ||
27 | #endif | ||
28 | #ifdef HAVE_WINSOCK2_H | ||
29 | #include <winsock2.h> | ||
30 | #endif], | ||
31 | [int x = AF_INET; struct in_addr y; struct sockaddr_in z; | ||
32 | if (&x && &y && &z) return 0;], | ||
33 | gl_cv_socket_ipv4=yes, gl_cv_socket_ipv4=no)]) | ||
34 | AC_MSG_RESULT($gl_cv_socket_ipv4) | ||
35 | if test $gl_cv_socket_ipv4 = yes; then | ||
36 | AC_DEFINE(HAVE_IPV4, 1, [Define to 1 if <sys/socket.h> defines AF_INET.]) | ||
37 | fi | ||
38 | |||
39 | AC_MSG_CHECKING(for IPv6 sockets) | ||
40 | AC_CACHE_VAL(gl_cv_socket_ipv6, | ||
41 | [AC_TRY_COMPILE([#include <sys/types.h> | ||
42 | #ifdef HAVE_SYS_SOCKET_H | ||
43 | #include <sys/socket.h> | ||
44 | #endif | ||
45 | #ifdef HAVE_NETINET_IN_H | ||
46 | #include <netinet/in.h> | ||
47 | #endif | ||
48 | #ifdef HAVE_WINSOCK2_H | ||
49 | #include <winsock2.h> | ||
50 | #endif], | ||
51 | [int x = AF_INET6; struct in6_addr y; struct sockaddr_in6 z; | ||
52 | if (&x && &y && &z) return 0;], | ||
53 | gl_cv_socket_ipv6=yes, gl_cv_socket_ipv6=no)]) | ||
54 | AC_MSG_RESULT($gl_cv_socket_ipv6) | ||
55 | if test $gl_cv_socket_ipv6 = yes; then | ||
56 | AC_DEFINE(HAVE_IPV6, 1, [Define to 1 if <sys/socket.h> defines AF_INET6.]) | ||
57 | fi | ||
58 | ]) | ||
diff --git a/gl/m4/ssize_t.m4 b/gl/m4/ssize_t.m4 new file mode 100644 index 00000000..4eaef93c --- /dev/null +++ b/gl/m4/ssize_t.m4 | |||
@@ -0,0 +1,21 @@ | |||
1 | # ssize_t.m4 serial 4 (gettext-0.15) | ||
2 | dnl Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | dnl Test whether ssize_t is defined. | ||
9 | |||
10 | AC_DEFUN([gt_TYPE_SSIZE_T], | ||
11 | [ | ||
12 | AC_CACHE_CHECK([for ssize_t], [gt_cv_ssize_t], | ||
13 | [AC_TRY_COMPILE([#include <sys/types.h>], | ||
14 | [int x = sizeof (ssize_t *) + sizeof (ssize_t); | ||
15 | return !x;], | ||
16 | [gt_cv_ssize_t=yes], [gt_cv_ssize_t=no])]) | ||
17 | if test $gt_cv_ssize_t = no; then | ||
18 | AC_DEFINE([ssize_t], [int], | ||
19 | [Define as a signed type of the same size as size_t.]) | ||
20 | fi | ||
21 | ]) | ||
diff --git a/gl/m4/stdbool.m4 b/gl/m4/stdbool.m4 new file mode 100644 index 00000000..2204ecd9 --- /dev/null +++ b/gl/m4/stdbool.m4 | |||
@@ -0,0 +1,115 @@ | |||
1 | # Check for stdbool.h that conforms to C99. | ||
2 | |||
3 | dnl Copyright (C) 2002-2006 Free Software Foundation, Inc. | ||
4 | dnl This file is free software; the Free Software Foundation | ||
5 | dnl gives unlimited permission to copy and/or distribute it, | ||
6 | dnl with or without modifications, as long as this notice is preserved. | ||
7 | |||
8 | # Prepare for substituting <stdbool.h> if it is not supported. | ||
9 | |||
10 | AC_DEFUN([AM_STDBOOL_H], | ||
11 | [ | ||
12 | AC_REQUIRE([AC_HEADER_STDBOOL]) | ||
13 | |||
14 | # Define two additional variables used in the Makefile substitution. | ||
15 | |||
16 | if test "$ac_cv_header_stdbool_h" = yes; then | ||
17 | STDBOOL_H='' | ||
18 | else | ||
19 | STDBOOL_H='stdbool.h' | ||
20 | fi | ||
21 | AC_SUBST([STDBOOL_H]) | ||
22 | |||
23 | if test "$ac_cv_type__Bool" = yes; then | ||
24 | HAVE__BOOL=1 | ||
25 | else | ||
26 | HAVE__BOOL=0 | ||
27 | fi | ||
28 | AC_SUBST([HAVE__BOOL]) | ||
29 | ]) | ||
30 | |||
31 | # AM_STDBOOL_H will be renamed to gl_STDBOOL_H in the future. | ||
32 | AC_DEFUN([gl_STDBOOL_H], [AM_STDBOOL_H]) | ||
33 | |||
34 | # This macro is only needed in autoconf <= 2.59. Newer versions of autoconf | ||
35 | # have this macro built-in. | ||
36 | |||
37 | AC_DEFUN([AC_HEADER_STDBOOL], | ||
38 | [AC_CACHE_CHECK([for stdbool.h that conforms to C99], | ||
39 | [ac_cv_header_stdbool_h], | ||
40 | [AC_TRY_COMPILE( | ||
41 | [ | ||
42 | #include <stdbool.h> | ||
43 | #ifndef bool | ||
44 | "error: bool is not defined" | ||
45 | #endif | ||
46 | #ifndef false | ||
47 | "error: false is not defined" | ||
48 | #endif | ||
49 | #if false | ||
50 | "error: false is not 0" | ||
51 | #endif | ||
52 | #ifndef true | ||
53 | "error: true is not defined" | ||
54 | #endif | ||
55 | #if true != 1 | ||
56 | "error: true is not 1" | ||
57 | #endif | ||
58 | #ifndef __bool_true_false_are_defined | ||
59 | "error: __bool_true_false_are_defined is not defined" | ||
60 | #endif | ||
61 | |||
62 | struct s { _Bool s: 1; _Bool t; } s; | ||
63 | |||
64 | char a[true == 1 ? 1 : -1]; | ||
65 | char b[false == 0 ? 1 : -1]; | ||
66 | char c[__bool_true_false_are_defined == 1 ? 1 : -1]; | ||
67 | char d[(bool) 0.5 == true ? 1 : -1]; | ||
68 | bool e = &s; | ||
69 | char f[(_Bool) 0.0 == false ? 1 : -1]; | ||
70 | char g[true]; | ||
71 | char h[sizeof (_Bool)]; | ||
72 | char i[sizeof s.t]; | ||
73 | enum { j = false, k = true, l = false * true, m = true * 256 }; | ||
74 | _Bool n[m]; | ||
75 | char o[sizeof n == m * sizeof n[0] ? 1 : -1]; | ||
76 | char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; | ||
77 | #if defined __xlc__ || defined __GNUC__ | ||
78 | /* Catch a bug in IBM AIX xlc compiler version 6.0.0.0 | ||
79 | reported by James Lemley on 2005-10-05; see | ||
80 | http://lists.gnu.org/archive/html/bug-coreutils/2005-10/msg00086.html | ||
81 | This test is not quite right, since xlc is allowed to | ||
82 | reject this program, as the initializer for xlcbug is | ||
83 | not one of the forms that C requires support for. | ||
84 | However, doing the test right would require a run-time | ||
85 | test, and that would make cross-compilation harder. | ||
86 | Let us hope that IBM fixes the xlc bug, and also adds | ||
87 | support for this kind of constant expression. In the | ||
88 | meantime, this test will reject xlc, which is OK, since | ||
89 | our stdbool.h substitute should suffice. We also test | ||
90 | this with GCC, where it should work, to detect more | ||
91 | quickly whether someone messes up the test in the | ||
92 | future. */ | ||
93 | char digs[] = "0123456789"; | ||
94 | int xlcbug = 1 / (&(digs + 5)[-2 + (bool) 1] == &digs[4] ? 1 : -1); | ||
95 | #endif | ||
96 | /* Catch a bug in an HP-UX C compiler. See | ||
97 | http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html | ||
98 | http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html | ||
99 | */ | ||
100 | _Bool q = true; | ||
101 | _Bool *pq = &q; | ||
102 | ], | ||
103 | [ | ||
104 | *pq |= q; | ||
105 | *pq |= ! q; | ||
106 | /* Refer to every declared value, to avoid compiler optimizations. */ | ||
107 | return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l | ||
108 | + !m + !n + !o + !p + !q + !pq); | ||
109 | ], | ||
110 | [ac_cv_header_stdbool_h=yes], | ||
111 | [ac_cv_header_stdbool_h=no])]) | ||
112 | AC_CHECK_TYPES([_Bool]) | ||
113 | if test $ac_cv_header_stdbool_h = yes; then | ||
114 | AC_DEFINE(HAVE_STDBOOL_H, 1, [Define to 1 if stdbool.h conforms to C99.]) | ||
115 | fi]) | ||
diff --git a/gl/m4/stdint.m4 b/gl/m4/stdint.m4 new file mode 100644 index 00000000..1a4b4a6a --- /dev/null +++ b/gl/m4/stdint.m4 | |||
@@ -0,0 +1,369 @@ | |||
1 | # stdint.m4 serial 22 | ||
2 | dnl Copyright (C) 2001-2002, 2004-2007 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Paul Eggert and Bruno Haible. | ||
8 | dnl Test whether <stdint.h> is supported or must be substituted. | ||
9 | |||
10 | AC_DEFUN([gl_STDINT_H], | ||
11 | [ | ||
12 | AC_PREREQ(2.59)dnl | ||
13 | |||
14 | dnl Check for long long int and unsigned long long int. | ||
15 | AC_REQUIRE([AC_TYPE_LONG_LONG_INT]) | ||
16 | if test $ac_cv_type_long_long_int = yes; then | ||
17 | HAVE_LONG_LONG_INT=1 | ||
18 | else | ||
19 | HAVE_LONG_LONG_INT=0 | ||
20 | fi | ||
21 | AC_SUBST([HAVE_LONG_LONG_INT]) | ||
22 | AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT]) | ||
23 | if test $ac_cv_type_unsigned_long_long_int = yes; then | ||
24 | HAVE_UNSIGNED_LONG_LONG_INT=1 | ||
25 | else | ||
26 | HAVE_UNSIGNED_LONG_LONG_INT=0 | ||
27 | fi | ||
28 | AC_SUBST([HAVE_UNSIGNED_LONG_LONG_INT]) | ||
29 | |||
30 | dnl Check for <inttypes.h>. | ||
31 | dnl AC_INCLUDES_DEFAULT defines $ac_cv_header_inttypes_h. | ||
32 | if test $ac_cv_header_inttypes_h = yes; then | ||
33 | HAVE_INTTYPES_H=1 | ||
34 | else | ||
35 | HAVE_INTTYPES_H=0 | ||
36 | fi | ||
37 | AC_SUBST([HAVE_INTTYPES_H]) | ||
38 | |||
39 | dnl Check for <sys/types.h>. | ||
40 | dnl AC_INCLUDES_DEFAULT defines $ac_cv_header_sys_types_h. | ||
41 | if test $ac_cv_header_sys_types_h = yes; then | ||
42 | HAVE_SYS_TYPES_H=1 | ||
43 | else | ||
44 | HAVE_SYS_TYPES_H=0 | ||
45 | fi | ||
46 | AC_SUBST([HAVE_SYS_TYPES_H]) | ||
47 | |||
48 | dnl AC_INCLUDES_DEFAULT defines $ac_cv_header_stdint_h. | ||
49 | if test $ac_cv_header_stdint_h = yes; then | ||
50 | gl_ABSOLUTE_HEADER([stdint.h]) | ||
51 | ABSOLUTE_STDINT_H=\"$gl_cv_absolute_stdint_h\" | ||
52 | HAVE_STDINT_H=1 | ||
53 | else | ||
54 | ABSOLUTE_STDINT_H=\"no/such/file/stdint.h\" | ||
55 | HAVE_STDINT_H=0 | ||
56 | fi | ||
57 | AC_SUBST([ABSOLUTE_STDINT_H]) | ||
58 | AC_SUBST([HAVE_STDINT_H]) | ||
59 | |||
60 | dnl Now see whether we need a substitute <stdint.h>. Use | ||
61 | dnl ABSOLUTE_STDINT_H, not <stdint.h>, so that it also works during | ||
62 | dnl a "config.status --recheck" if a stdint.h has been | ||
63 | dnl created in the build directory. | ||
64 | if test $ac_cv_header_stdint_h = yes; then | ||
65 | AC_CACHE_CHECK([whether stdint.h conforms to C99], | ||
66 | [gl_cv_header_working_stdint_h], | ||
67 | [gl_cv_header_working_stdint_h=no | ||
68 | AC_COMPILE_IFELSE([ | ||
69 | AC_LANG_PROGRAM([[ | ||
70 | #include <stddef.h> | ||
71 | #define __STDC_LIMIT_MACROS 1 /* to make it work also in C++ mode */ | ||
72 | #define __STDC_CONSTANT_MACROS 1 /* to make it work also in C++ mode */ | ||
73 | #include ABSOLUTE_STDINT_H | ||
74 | #ifdef INT8_MAX | ||
75 | int8_t a1 = INT8_MAX; | ||
76 | int8_t a1min = INT8_MIN; | ||
77 | #endif | ||
78 | #ifdef INT16_MAX | ||
79 | int16_t a2 = INT16_MAX; | ||
80 | int16_t a2min = INT16_MIN; | ||
81 | #endif | ||
82 | #ifdef INT32_MAX | ||
83 | int32_t a3 = INT32_MAX; | ||
84 | int32_t a3min = INT32_MIN; | ||
85 | #endif | ||
86 | #ifdef INT64_MAX | ||
87 | int64_t a4 = INT64_MAX; | ||
88 | int64_t a4min = INT64_MIN; | ||
89 | #endif | ||
90 | #ifdef UINT8_MAX | ||
91 | uint8_t b1 = UINT8_MAX; | ||
92 | #else | ||
93 | typedef int b1[(unsigned char) -1 != 255 ? 1 : -1]; | ||
94 | #endif | ||
95 | #ifdef UINT16_MAX | ||
96 | uint16_t b2 = UINT16_MAX; | ||
97 | #endif | ||
98 | #ifdef UINT32_MAX | ||
99 | uint32_t b3 = UINT32_MAX; | ||
100 | #endif | ||
101 | #ifdef UINT64_MAX | ||
102 | uint64_t b4 = UINT64_MAX; | ||
103 | #endif | ||
104 | int_least8_t c1 = INT8_C (0x7f); | ||
105 | int_least8_t c1max = INT_LEAST8_MAX; | ||
106 | int_least8_t c1min = INT_LEAST8_MIN; | ||
107 | int_least16_t c2 = INT16_C (0x7fff); | ||
108 | int_least16_t c2max = INT_LEAST16_MAX; | ||
109 | int_least16_t c2min = INT_LEAST16_MIN; | ||
110 | int_least32_t c3 = INT32_C (0x7fffffff); | ||
111 | int_least32_t c3max = INT_LEAST32_MAX; | ||
112 | int_least32_t c3min = INT_LEAST32_MIN; | ||
113 | int_least64_t c4 = INT64_C (0x7fffffffffffffff); | ||
114 | int_least64_t c4max = INT_LEAST64_MAX; | ||
115 | int_least64_t c4min = INT_LEAST64_MIN; | ||
116 | uint_least8_t d1 = UINT8_C (0xff); | ||
117 | uint_least8_t d1max = UINT_LEAST8_MAX; | ||
118 | uint_least16_t d2 = UINT16_C (0xffff); | ||
119 | uint_least16_t d2max = UINT_LEAST16_MAX; | ||
120 | uint_least32_t d3 = UINT32_C (0xffffffff); | ||
121 | uint_least32_t d3max = UINT_LEAST32_MAX; | ||
122 | uint_least64_t d4 = UINT64_C (0xffffffffffffffff); | ||
123 | uint_least64_t d4max = UINT_LEAST64_MAX; | ||
124 | int_fast8_t e1 = INT_FAST8_MAX; | ||
125 | int_fast8_t e1min = INT_FAST8_MIN; | ||
126 | int_fast16_t e2 = INT_FAST16_MAX; | ||
127 | int_fast16_t e2min = INT_FAST16_MIN; | ||
128 | int_fast32_t e3 = INT_FAST32_MAX; | ||
129 | int_fast32_t e3min = INT_FAST32_MIN; | ||
130 | int_fast64_t e4 = INT_FAST64_MAX; | ||
131 | int_fast64_t e4min = INT_FAST64_MIN; | ||
132 | uint_fast8_t f1 = UINT_FAST8_MAX; | ||
133 | uint_fast16_t f2 = UINT_FAST16_MAX; | ||
134 | uint_fast32_t f3 = UINT_FAST32_MAX; | ||
135 | uint_fast64_t f4 = UINT_FAST64_MAX; | ||
136 | #ifdef INTPTR_MAX | ||
137 | intptr_t g = INTPTR_MAX; | ||
138 | intptr_t gmin = INTPTR_MIN; | ||
139 | #endif | ||
140 | #ifdef UINTPTR_MAX | ||
141 | uintptr_t h = UINTPTR_MAX; | ||
142 | #endif | ||
143 | intmax_t i = INTMAX_MAX; | ||
144 | uintmax_t j = UINTMAX_MAX; | ||
145 | struct s { | ||
146 | int check_PTRDIFF: PTRDIFF_MIN < 0 && 0 < PTRDIFF_MAX ? 1 : -1; | ||
147 | int check_SIG_ATOMIC: SIG_ATOMIC_MIN <= 0 && 0 < SIG_ATOMIC_MAX ? 1 : -1; | ||
148 | int check_SIZE: 0 < SIZE_MAX ? 1 : -1; | ||
149 | int check_WCHAR: WCHAR_MIN <= 0 && 0 < WCHAR_MAX ? 1 : -1; | ||
150 | int check_WINT: WINT_MIN <= 0 && 0 < WINT_MAX ? 1 : -1; | ||
151 | |||
152 | /* Detect bugs in glibc 2.4 and Solaris 10 stdint.h, among others. */ | ||
153 | int check_UINT8_C: | ||
154 | (-1 < UINT8_C (0)) == (-1 < (uint_least8_t) 0) ? 1 : -1; | ||
155 | int check_UINT16_C: | ||
156 | (-1 < UINT16_C (0)) == (-1 < (uint_least16_t) 0) ? 1 : -1; | ||
157 | |||
158 | /* Detect bugs in OpenBSD 3.9 stdint.h. */ | ||
159 | #ifdef UINT8_MAX | ||
160 | int check_uint8: (uint8_t) -1 == UINT8_MAX ? 1 : -1; | ||
161 | #endif | ||
162 | #ifdef UINT16_MAX | ||
163 | int check_uint16: (uint16_t) -1 == UINT16_MAX ? 1 : -1; | ||
164 | #endif | ||
165 | #ifdef UINT32_MAX | ||
166 | int check_uint32: (uint32_t) -1 == UINT32_MAX ? 1 : -1; | ||
167 | #endif | ||
168 | #ifdef UINT64_MAX | ||
169 | int check_uint64: (uint64_t) -1 == UINT64_MAX ? 1 : -1; | ||
170 | #endif | ||
171 | int check_uint_least8: (uint_least8_t) -1 == UINT_LEAST8_MAX ? 1 : -1; | ||
172 | int check_uint_least16: (uint_least16_t) -1 == UINT_LEAST16_MAX ? 1 : -1; | ||
173 | int check_uint_least32: (uint_least32_t) -1 == UINT_LEAST32_MAX ? 1 : -1; | ||
174 | int check_uint_least64: (uint_least64_t) -1 == UINT_LEAST64_MAX ? 1 : -1; | ||
175 | int check_uint_fast8: (uint_fast8_t) -1 == UINT_FAST8_MAX ? 1 : -1; | ||
176 | int check_uint_fast16: (uint_fast16_t) -1 == UINT_FAST16_MAX ? 1 : -1; | ||
177 | int check_uint_fast32: (uint_fast32_t) -1 == UINT_FAST32_MAX ? 1 : -1; | ||
178 | int check_uint_fast64: (uint_fast64_t) -1 == UINT_FAST64_MAX ? 1 : -1; | ||
179 | int check_uintptr: (uintptr_t) -1 == UINTPTR_MAX ? 1 : -1; | ||
180 | int check_uintmax: (uintmax_t) -1 == UINTMAX_MAX ? 1 : -1; | ||
181 | int check_size: (size_t) -1 == SIZE_MAX ? 1 : -1; | ||
182 | }; | ||
183 | ]])], | ||
184 | [gl_cv_header_working_stdint_h=yes])]) | ||
185 | fi | ||
186 | if test "$gl_cv_header_working_stdint_h" = yes; then | ||
187 | STDINT_H= | ||
188 | else | ||
189 | dnl Check for <sys/inttypes.h>, and for | ||
190 | dnl <sys/bitypes.h> (used in Linux libc4 >= 4.6.7 and libc5). | ||
191 | AC_CHECK_HEADERS([sys/inttypes.h sys/bitypes.h]) | ||
192 | if test $ac_cv_header_sys_inttypes_h = yes; then | ||
193 | HAVE_SYS_INTTYPES_H=1 | ||
194 | else | ||
195 | HAVE_SYS_INTTYPES_H=0 | ||
196 | fi | ||
197 | AC_SUBST([HAVE_SYS_INTTYPES_H]) | ||
198 | if test $ac_cv_header_sys_bitypes_h = yes; then | ||
199 | HAVE_SYS_BITYPES_H=1 | ||
200 | else | ||
201 | HAVE_SYS_BITYPES_H=0 | ||
202 | fi | ||
203 | AC_SUBST([HAVE_SYS_BITYPES_H]) | ||
204 | |||
205 | gl_STDINT_TYPE_PROPERTIES | ||
206 | STDINT_H=stdint.h | ||
207 | fi | ||
208 | AC_SUBST(STDINT_H) | ||
209 | ]) | ||
210 | |||
211 | dnl gl_STDINT_BITSIZEOF(TYPES, INCLUDES) | ||
212 | dnl Determine the size of each of the given types in bits. | ||
213 | AC_DEFUN([gl_STDINT_BITSIZEOF], | ||
214 | [ | ||
215 | dnl Use a shell loop, to avoid bloating configure, and | ||
216 | dnl - extra AH_TEMPLATE calls, so that autoheader knows what to put into | ||
217 | dnl config.h.in, | ||
218 | dnl - extra AC_SUBST calls, so that the right substitutions are made. | ||
219 | AC_FOREACH([gltype], [$1], | ||
220 | [AH_TEMPLATE([BITSIZEOF_]translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]), | ||
221 | [Define to the number of bits in type ']gltype['.])]) | ||
222 | for gltype in $1 ; do | ||
223 | AC_CACHE_CHECK([for bit size of $gltype], [gl_cv_bitsizeof_${gltype}], | ||
224 | [AC_COMPUTE_INT([result], [sizeof ($gltype) * CHAR_BIT], | ||
225 | [$2 | ||
226 | #include <limits.h>], [result=unknown]) | ||
227 | eval gl_cv_bitsizeof_${gltype}=\$result | ||
228 | ]) | ||
229 | eval result=\$gl_cv_bitsizeof_${gltype} | ||
230 | if test $result = unknown; then | ||
231 | dnl Use a nonempty default, because some compilers, such as IRIX 5 cc, | ||
232 | dnl do a syntax check even on unused #if conditions and give an error | ||
233 | dnl on valid C code like this: | ||
234 | dnl #if 0 | ||
235 | dnl # if > 32 | ||
236 | dnl # endif | ||
237 | dnl #endif | ||
238 | result=0 | ||
239 | fi | ||
240 | GLTYPE=`echo "$gltype" | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'` | ||
241 | AC_DEFINE_UNQUOTED([BITSIZEOF_${GLTYPE}], [$result]) | ||
242 | eval BITSIZEOF_${GLTYPE}=\$result | ||
243 | done | ||
244 | AC_FOREACH([gltype], [$1], | ||
245 | [AC_SUBST([BITSIZEOF_]translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]))]) | ||
246 | ]) | ||
247 | |||
248 | dnl gl_CHECK_TYPES_SIGNED(TYPES, INCLUDES) | ||
249 | dnl Determine the signedness of each of the given types. | ||
250 | dnl Define HAVE_SIGNED_TYPE if type is signed. | ||
251 | AC_DEFUN([gl_CHECK_TYPES_SIGNED], | ||
252 | [ | ||
253 | dnl Use a shell loop, to avoid bloating configure, and | ||
254 | dnl - extra AH_TEMPLATE calls, so that autoheader knows what to put into | ||
255 | dnl config.h.in, | ||
256 | dnl - extra AC_SUBST calls, so that the right substitutions are made. | ||
257 | AC_FOREACH([gltype], [$1], | ||
258 | [AH_TEMPLATE([HAVE_SIGNED_]translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]), | ||
259 | [Define to 1 if ']gltype[' is a signed integer type.])]) | ||
260 | for gltype in $1 ; do | ||
261 | AC_CACHE_CHECK([whether $gltype is signed], [gl_cv_type_${gltype}_signed], | ||
262 | [AC_COMPILE_IFELSE( | ||
263 | [AC_LANG_PROGRAM([$2[ | ||
264 | int verify[2 * (($gltype) -1 < ($gltype) 0) - 1];]])], | ||
265 | result=yes, result=no) | ||
266 | eval gl_cv_type_${gltype}_signed=\$result | ||
267 | ]) | ||
268 | eval result=\$gl_cv_type_${gltype}_signed | ||
269 | GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'` | ||
270 | if test "$result" = yes; then | ||
271 | AC_DEFINE_UNQUOTED([HAVE_SIGNED_${GLTYPE}], 1) | ||
272 | eval HAVE_SIGNED_${GLTYPE}=1 | ||
273 | else | ||
274 | eval HAVE_SIGNED_${GLTYPE}=0 | ||
275 | fi | ||
276 | done | ||
277 | AC_FOREACH([gltype], [$1], | ||
278 | [AC_SUBST([HAVE_SIGNED_]translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_]))]) | ||
279 | ]) | ||
280 | |||
281 | dnl gl_INTEGER_TYPE_SUFFIX(TYPES, INCLUDES) | ||
282 | dnl Determine the suffix to use for integer constants of the given types. | ||
283 | dnl Define t_SUFFIX for each such type. | ||
284 | AC_DEFUN([gl_INTEGER_TYPE_SUFFIX], | ||
285 | [ | ||
286 | dnl Use a shell loop, to avoid bloating configure, and | ||
287 | dnl - extra AH_TEMPLATE calls, so that autoheader knows what to put into | ||
288 | dnl config.h.in, | ||
289 | dnl - extra AC_SUBST calls, so that the right substitutions are made. | ||
290 | AC_FOREACH([gltype], [$1], | ||
291 | [AH_TEMPLATE(translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_])[_SUFFIX], | ||
292 | [Define to l, ll, u, ul, ull, etc., as suitable for | ||
293 | constants of type ']gltype['.])]) | ||
294 | for gltype in $1 ; do | ||
295 | AC_CACHE_CHECK([for $gltype integer literal suffix], | ||
296 | [gl_cv_type_${gltype}_suffix], | ||
297 | [eval gl_cv_type_${gltype}_suffix=no | ||
298 | eval result=\$gl_cv_type_${gltype}_signed | ||
299 | if test "$result" = yes; then | ||
300 | glsufu= | ||
301 | else | ||
302 | glsufu=u | ||
303 | fi | ||
304 | for glsuf in "$glsufu" ${glsufu}l ${glsufu}ll ${glsufu}i64; do | ||
305 | case $glsuf in | ||
306 | '') gltype1='int';; | ||
307 | l) gltype1='long int';; | ||
308 | ll) gltype1='long long int';; | ||
309 | i64) gltype1='__int64';; | ||
310 | u) gltype1='unsigned int';; | ||
311 | ul) gltype1='unsigned long int';; | ||
312 | ull) gltype1='unsigned long long int';; | ||
313 | ui64)gltype1='unsigned __int64';; | ||
314 | esac | ||
315 | AC_COMPILE_IFELSE( | ||
316 | [AC_LANG_PROGRAM([$2 | ||
317 | extern $gltype foo; | ||
318 | extern $gltype1 foo;])], | ||
319 | [eval gl_cv_type_${gltype}_suffix=\$glsuf]) | ||
320 | eval result=\$gl_cv_type_${gltype}_suffix | ||
321 | test "$result" != no && break | ||
322 | done]) | ||
323 | GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'` | ||
324 | eval result=\$gl_cv_type_${gltype}_suffix | ||
325 | test "$result" = no && result= | ||
326 | eval ${GLTYPE}_SUFFIX=\$result | ||
327 | AC_DEFINE_UNQUOTED([${GLTYPE}_SUFFIX], $result) | ||
328 | done | ||
329 | AC_FOREACH([gltype], [$1], | ||
330 | [AC_SUBST(translit(gltype,[abcdefghijklmnopqrstuvwxyz ],[ABCDEFGHIJKLMNOPQRSTUVWXYZ_])[_SUFFIX])]) | ||
331 | ]) | ||
332 | |||
333 | dnl gl_STDINT_INCLUDES | ||
334 | AC_DEFUN([gl_STDINT_INCLUDES], | ||
335 | [[ | ||
336 | /* BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be | ||
337 | included before <wchar.h>. */ | ||
338 | #include <stddef.h> | ||
339 | #include <signal.h> | ||
340 | #include <stdio.h> | ||
341 | #include <time.h> | ||
342 | #include <wchar.h> | ||
343 | ]]) | ||
344 | |||
345 | dnl gl_STDINT_TYPE_PROPERTIES | ||
346 | dnl Compute HAVE_SIGNED_t, BITSIZEOF_t and t_SUFFIX, for all the types t | ||
347 | dnl of interest to stdint_.h. | ||
348 | AC_DEFUN([gl_STDINT_TYPE_PROPERTIES], | ||
349 | [ | ||
350 | gl_STDINT_BITSIZEOF([ptrdiff_t sig_atomic_t size_t wchar_t wint_t], | ||
351 | [gl_STDINT_INCLUDES]) | ||
352 | gl_CHECK_TYPES_SIGNED([sig_atomic_t wchar_t wint_t], | ||
353 | [gl_STDINT_INCLUDES]) | ||
354 | gl_cv_type_ptrdiff_t_signed=yes | ||
355 | gl_cv_type_size_t_signed=no | ||
356 | gl_INTEGER_TYPE_SUFFIX([ptrdiff_t sig_atomic_t size_t wchar_t wint_t], | ||
357 | [gl_STDINT_INCLUDES]) | ||
358 | ]) | ||
359 | |||
360 | dnl Autoconf >= 2.61 has AC_COMPUTE_INT built-in. | ||
361 | dnl Remove this when we can assume autoconf >= 2.61. | ||
362 | m4_ifdef([AC_COMPUTE_INT], [], [ | ||
363 | AC_DEFUN([AC_COMPUTE_INT], [_AC_COMPUTE_INT([$2],[$1],[$3],[$4])]) | ||
364 | ]) | ||
365 | |||
366 | # Hey Emacs! | ||
367 | # Local Variables: | ||
368 | # indent-tabs-mode: nil | ||
369 | # End: | ||
diff --git a/gl/m4/stdint_h.m4 b/gl/m4/stdint_h.m4 new file mode 100644 index 00000000..db9a8ac4 --- /dev/null +++ b/gl/m4/stdint_h.m4 | |||
@@ -0,0 +1,26 @@ | |||
1 | # stdint_h.m4 serial 6 | ||
2 | dnl Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Paul Eggert. | ||
8 | |||
9 | # Define HAVE_STDINT_H_WITH_UINTMAX if <stdint.h> exists, | ||
10 | # doesn't clash with <sys/types.h>, and declares uintmax_t. | ||
11 | |||
12 | AC_DEFUN([gl_AC_HEADER_STDINT_H], | ||
13 | [ | ||
14 | AC_CACHE_CHECK([for stdint.h], gl_cv_header_stdint_h, | ||
15 | [AC_TRY_COMPILE( | ||
16 | [#include <sys/types.h> | ||
17 | #include <stdint.h>], | ||
18 | [uintmax_t i = (uintmax_t) -1; return !i;], | ||
19 | gl_cv_header_stdint_h=yes, | ||
20 | gl_cv_header_stdint_h=no)]) | ||
21 | if test $gl_cv_header_stdint_h = yes; then | ||
22 | AC_DEFINE_UNQUOTED(HAVE_STDINT_H_WITH_UINTMAX, 1, | ||
23 | [Define if <stdint.h> exists, doesn't clash with <sys/types.h>, | ||
24 | and declares uintmax_t. ]) | ||
25 | fi | ||
26 | ]) | ||
diff --git a/gl/m4/strcase.m4 b/gl/m4/strcase.m4 new file mode 100644 index 00000000..ae827907 --- /dev/null +++ b/gl/m4/strcase.m4 | |||
@@ -0,0 +1,39 @@ | |||
1 | # strcase.m4 serial 4 | ||
2 | dnl Copyright (C) 2002, 2005-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_STRCASE], | ||
8 | [ | ||
9 | gl_FUNC_STRCASECMP | ||
10 | gl_FUNC_STRNCASECMP | ||
11 | ]) | ||
12 | |||
13 | AC_DEFUN([gl_FUNC_STRCASECMP], | ||
14 | [ | ||
15 | dnl No known system has a strcasecmp() function that works correctly in | ||
16 | dnl multibyte locales. Therefore we use our version always. | ||
17 | AC_LIBOBJ(strcasecmp) | ||
18 | gl_PREREQ_STRCASECMP | ||
19 | ]) | ||
20 | |||
21 | AC_DEFUN([gl_FUNC_STRNCASECMP], | ||
22 | [ | ||
23 | AC_REPLACE_FUNCS(strncasecmp) | ||
24 | AC_CHECK_DECLS(strncasecmp) | ||
25 | if test $ac_cv_func_strncasecmp = no; then | ||
26 | gl_PREREQ_STRNCASECMP | ||
27 | fi | ||
28 | ]) | ||
29 | |||
30 | # Prerequisites of lib/strcasecmp.c. | ||
31 | AC_DEFUN([gl_PREREQ_STRCASECMP], [ | ||
32 | AC_REQUIRE([gl_FUNC_MBRTOWC]) | ||
33 | : | ||
34 | ]) | ||
35 | |||
36 | # Prerequisites of lib/strncasecmp.c. | ||
37 | AC_DEFUN([gl_PREREQ_STRNCASECMP], [ | ||
38 | : | ||
39 | ]) | ||
diff --git a/gl/m4/strdup.m4 b/gl/m4/strdup.m4 new file mode 100644 index 00000000..f7786e94 --- /dev/null +++ b/gl/m4/strdup.m4 | |||
@@ -0,0 +1,15 @@ | |||
1 | # strdup.m4 serial 7 | ||
2 | dnl Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FUNC_STRDUP], | ||
8 | [ | ||
9 | AC_REPLACE_FUNCS(strdup) | ||
10 | AC_CHECK_DECLS_ONCE(strdup) | ||
11 | gl_PREREQ_STRDUP | ||
12 | ]) | ||
13 | |||
14 | # Prerequisites of lib/strdup.c. | ||
15 | AC_DEFUN([gl_PREREQ_STRDUP], [:]) | ||
diff --git a/gl/m4/strndup.m4 b/gl/m4/strndup.m4 new file mode 100644 index 00000000..dd5780b6 --- /dev/null +++ b/gl/m4/strndup.m4 | |||
@@ -0,0 +1,48 @@ | |||
1 | # strndup.m4 serial 11 | ||
2 | dnl Copyright (C) 2002-2003, 2005-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FUNC_STRNDUP], | ||
8 | [ | ||
9 | dnl Persuade glibc <string.h> to declare strndup(). | ||
10 | AC_REQUIRE([AC_GNU_SOURCE]) | ||
11 | |||
12 | AC_CHECK_DECLS_ONCE([strndup]) | ||
13 | |||
14 | # AIX 4.3.3, AIX 5.1 have a function that fails to add the terminating '\0'. | ||
15 | AC_CACHE_CHECK([for working strndup], gl_cv_func_strndup, | ||
16 | [AC_RUN_IFELSE([ | ||
17 | AC_LANG_PROGRAM([#include <string.h> | ||
18 | #include <stdlib.h>], [[ | ||
19 | #ifndef HAVE_DECL_STRNDUP | ||
20 | extern char *strndup (const char *, size_t); | ||
21 | #endif | ||
22 | char *s; | ||
23 | s = strndup ("some longer string", 15); | ||
24 | free (s); | ||
25 | s = strndup ("shorter string", 13); | ||
26 | return s[13] != '\0';]])], | ||
27 | [gl_cv_func_strndup=yes], | ||
28 | [gl_cv_func_strndup=no], | ||
29 | [AC_CHECK_FUNC([strndup], | ||
30 | [AC_EGREP_CPP([too risky], [ | ||
31 | #ifdef _AIX | ||
32 | too risky | ||
33 | #endif | ||
34 | ], | ||
35 | [gl_cv_func_strndup=no], | ||
36 | [gl_cv_func_strndup=yes])], | ||
37 | [gl_cv_func_strndup=no])])]) | ||
38 | if test $gl_cv_func_strndup = yes; then | ||
39 | AC_DEFINE([HAVE_STRNDUP], 1, | ||
40 | [Define if you have the strndup() function and it works.]) | ||
41 | else | ||
42 | AC_LIBOBJ([strndup]) | ||
43 | gl_PREREQ_STRNDUP | ||
44 | fi | ||
45 | ]) | ||
46 | |||
47 | # Prerequisites of lib/strndup.c. | ||
48 | AC_DEFUN([gl_PREREQ_STRNDUP], [:]) | ||
diff --git a/gl/m4/strnlen.m4 b/gl/m4/strnlen.m4 new file mode 100644 index 00000000..0213a8ae --- /dev/null +++ b/gl/m4/strnlen.m4 | |||
@@ -0,0 +1,27 @@ | |||
1 | # strnlen.m4 serial 6 | ||
2 | dnl Copyright (C) 2002-2003, 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FUNC_STRNLEN], | ||
8 | [ | ||
9 | dnl Persuade glibc <string.h> to declare strnlen(). | ||
10 | AC_REQUIRE([AC_GNU_SOURCE]) | ||
11 | |||
12 | AC_FUNC_STRNLEN | ||
13 | if test $ac_cv_func_strnlen_working = no; then | ||
14 | # This is necessary because automake-1.6.1 doens't understand | ||
15 | # that the above use of AC_FUNC_STRNLEN means we may have to use | ||
16 | # lib/strnlen.c. | ||
17 | #AC_LIBOBJ(strnlen) | ||
18 | AC_DEFINE(strnlen, rpl_strnlen, | ||
19 | [Define to rpl_strnlen if the replacement function should be used.]) | ||
20 | gl_PREREQ_STRNLEN | ||
21 | fi | ||
22 | ]) | ||
23 | |||
24 | # Prerequisites of lib/strnlen.c. | ||
25 | AC_DEFUN([gl_PREREQ_STRNLEN], [ | ||
26 | AC_CHECK_DECLS_ONCE(strnlen) | ||
27 | ]) | ||
diff --git a/gl/m4/sys_socket_h.m4 b/gl/m4/sys_socket_h.m4 new file mode 100644 index 00000000..d3e45b48 --- /dev/null +++ b/gl/m4/sys_socket_h.m4 | |||
@@ -0,0 +1,23 @@ | |||
1 | # sys_socket_h.m4 serial 2 | ||
2 | dnl Copyright (C) 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Simon Josefsson. | ||
8 | |||
9 | AC_DEFUN([gl_HEADER_SYS_SOCKET], | ||
10 | [ | ||
11 | AC_CHECK_HEADERS_ONCE([sys/socket.h]) | ||
12 | if test $ac_cv_header_sys_socket_h = yes; then | ||
13 | SYS_SOCKET_H='' | ||
14 | else | ||
15 | dnl We cannot use AC_CHECK_HEADERS_ONCE here, because that would make | ||
16 | dnl the check for those headers unconditional; yet cygwin reports | ||
17 | dnl that the headers are present but cannot be compiled (since on | ||
18 | dnl cygwin, all socket information should come from sys/socket.h). | ||
19 | AC_CHECK_HEADERS([winsock2.h ws2tcpip.h]) | ||
20 | SYS_SOCKET_H='sys/socket.h' | ||
21 | fi | ||
22 | AC_SUBST(SYS_SOCKET_H) | ||
23 | ]) | ||
diff --git a/gl/m4/uintmax_t.m4 b/gl/m4/uintmax_t.m4 new file mode 100644 index 00000000..bf83ed74 --- /dev/null +++ b/gl/m4/uintmax_t.m4 | |||
@@ -0,0 +1,30 @@ | |||
1 | # uintmax_t.m4 serial 9 | ||
2 | dnl Copyright (C) 1997-2004 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Paul Eggert. | ||
8 | |||
9 | AC_PREREQ(2.13) | ||
10 | |||
11 | # Define uintmax_t to 'unsigned long' or 'unsigned long long' | ||
12 | # if it is not already defined in <stdint.h> or <inttypes.h>. | ||
13 | |||
14 | AC_DEFUN([gl_AC_TYPE_UINTMAX_T], | ||
15 | [ | ||
16 | AC_REQUIRE([gl_AC_HEADER_INTTYPES_H]) | ||
17 | AC_REQUIRE([gl_AC_HEADER_STDINT_H]) | ||
18 | if test $gl_cv_header_inttypes_h = no && test $gl_cv_header_stdint_h = no; then | ||
19 | AC_REQUIRE([gl_AC_TYPE_UNSIGNED_LONG_LONG]) | ||
20 | test $ac_cv_type_unsigned_long_long = yes \ | ||
21 | && ac_type='unsigned long long' \ | ||
22 | || ac_type='unsigned long' | ||
23 | AC_DEFINE_UNQUOTED(uintmax_t, $ac_type, | ||
24 | [Define to unsigned long or unsigned long long | ||
25 | if <stdint.h> and <inttypes.h> don't define.]) | ||
26 | else | ||
27 | AC_DEFINE(HAVE_UINTMAX_T, 1, | ||
28 | [Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>.]) | ||
29 | fi | ||
30 | ]) | ||
diff --git a/gl/m4/ulonglong.m4 b/gl/m4/ulonglong.m4 new file mode 100644 index 00000000..9fae98e3 --- /dev/null +++ b/gl/m4/ulonglong.m4 | |||
@@ -0,0 +1,48 @@ | |||
1 | # ulonglong.m4 serial 6 | ||
2 | dnl Copyright (C) 1999-2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Paul Eggert. | ||
8 | |||
9 | # Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works. | ||
10 | # This fixes a bug in Autoconf 2.60, but can be removed once we | ||
11 | # assume 2.61 everywhere. | ||
12 | |||
13 | # Note: If the type 'unsigned long long int' exists but is only 32 bits | ||
14 | # large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT | ||
15 | # will not be defined. In this case you can treat 'unsigned long long int' | ||
16 | # like 'unsigned long int'. | ||
17 | |||
18 | AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT], | ||
19 | [ | ||
20 | AC_CACHE_CHECK([for unsigned long long int], | ||
21 | [ac_cv_type_unsigned_long_long_int], | ||
22 | [AC_LINK_IFELSE( | ||
23 | [AC_LANG_PROGRAM( | ||
24 | [[unsigned long long int ull = 18446744073709551615ULL; | ||
25 | typedef int a[(18446744073709551615ULL <= (unsigned long long int) -1 | ||
26 | ? 1 : -1)]; | ||
27 | int i = 63;]], | ||
28 | [[unsigned long long int ullmax = 18446744073709551615ull; | ||
29 | return (ull << 63 | ull >> 63 | ull << i | ull >> i | ||
30 | | ullmax / ull | ullmax % ull);]])], | ||
31 | [ac_cv_type_unsigned_long_long_int=yes], | ||
32 | [ac_cv_type_unsigned_long_long_int=no])]) | ||
33 | if test $ac_cv_type_unsigned_long_long_int = yes; then | ||
34 | AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], 1, | ||
35 | [Define to 1 if the system has the type `unsigned long long int'.]) | ||
36 | fi | ||
37 | ]) | ||
38 | |||
39 | # This macro is obsolescent and should go away soon. | ||
40 | AC_DEFUN([gl_AC_TYPE_UNSIGNED_LONG_LONG], | ||
41 | [ | ||
42 | AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT]) | ||
43 | ac_cv_type_unsigned_long_long=$ac_cv_type_unsigned_long_long_int | ||
44 | if test $ac_cv_type_unsigned_long_long = yes; then | ||
45 | AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1, | ||
46 | [Define if you have the 'unsigned long long' type.]) | ||
47 | fi | ||
48 | ]) | ||
diff --git a/gl/m4/unistd-safer.m4 b/gl/m4/unistd-safer.m4 new file mode 100644 index 00000000..09adf931 --- /dev/null +++ b/gl/m4/unistd-safer.m4 | |||
@@ -0,0 +1,13 @@ | |||
1 | #serial 8 | ||
2 | dnl Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_UNISTD_SAFER], | ||
8 | [ | ||
9 | AC_CHECK_FUNCS_ONCE([pipe]) | ||
10 | AC_LIBOBJ([dup-safer]) | ||
11 | AC_LIBOBJ([fd-safer]) | ||
12 | AC_LIBOBJ([pipe-safer]) | ||
13 | ]) | ||
diff --git a/gl/m4/unistd_h.m4 b/gl/m4/unistd_h.m4 new file mode 100644 index 00000000..9d499dfe --- /dev/null +++ b/gl/m4/unistd_h.m4 | |||
@@ -0,0 +1,32 @@ | |||
1 | # unistd_h.m4 serial 3 | ||
2 | dnl Copyright (C) 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl Written by Simon Josefsson | ||
8 | |||
9 | AC_DEFUN([gl_HEADER_UNISTD], | ||
10 | [ | ||
11 | AC_CHECK_HEADERS([unistd.h], [ | ||
12 | UNISTD_H='' | ||
13 | ], [ | ||
14 | UNISTD_H='unistd.h' | ||
15 | ]) | ||
16 | AC_SUBST(UNISTD_H) | ||
17 | dnl This module decides to build unistd.h if it is missing. | ||
18 | dnl The fchdir module decides to build unistd.h if fchdir() is missing. | ||
19 | dnl Therefore check for the prerequisites of lib/unistd.h always. | ||
20 | gl_PREREQ_UNISTD | ||
21 | ]) | ||
22 | |||
23 | dnl Prerequisites of lib/unistd.h. | ||
24 | AC_DEFUN([gl_PREREQ_UNISTD], | ||
25 | [ | ||
26 | AC_CHECK_HEADERS_ONCE([unistd.h]) | ||
27 | if test $ac_cv_header_unistd_h = yes; then | ||
28 | gl_ABSOLUTE_HEADER([unistd.h]) | ||
29 | ABSOLUTE_UNISTD_H=\"$gl_cv_absolute_unistd_h\" | ||
30 | fi | ||
31 | AC_SUBST([ABSOLUTE_UNISTD_H]) | ||
32 | ]) | ||
diff --git a/gl/m4/vasnprintf.m4 b/gl/m4/vasnprintf.m4 new file mode 100644 index 00000000..72c9a13e --- /dev/null +++ b/gl/m4/vasnprintf.m4 | |||
@@ -0,0 +1,57 @@ | |||
1 | # vasnprintf.m4 serial 7 | ||
2 | dnl Copyright (C) 2002-2004, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FUNC_VASNPRINTF], | ||
8 | [ | ||
9 | AC_REQUIRE([gl_EOVERFLOW]) | ||
10 | AC_REPLACE_FUNCS(vasnprintf) | ||
11 | if test $ac_cv_func_vasnprintf = no; then | ||
12 | AC_LIBOBJ(printf-args) | ||
13 | AC_LIBOBJ(printf-parse) | ||
14 | AC_LIBOBJ(asnprintf) | ||
15 | gl_PREREQ_PRINTF_ARGS | ||
16 | gl_PREREQ_PRINTF_PARSE | ||
17 | gl_PREREQ_VASNPRINTF | ||
18 | gl_PREREQ_ASNPRINTF | ||
19 | fi | ||
20 | ]) | ||
21 | |||
22 | # Prequisites of lib/printf-args.h, lib/printf-args.c. | ||
23 | AC_DEFUN([gl_PREREQ_PRINTF_ARGS], | ||
24 | [ | ||
25 | AC_REQUIRE([AC_TYPE_LONG_LONG_INT]) | ||
26 | AC_REQUIRE([gt_TYPE_LONGDOUBLE]) | ||
27 | AC_REQUIRE([gt_TYPE_WCHAR_T]) | ||
28 | AC_REQUIRE([gt_TYPE_WINT_T]) | ||
29 | ]) | ||
30 | |||
31 | # Prequisites of lib/printf-parse.h, lib/printf-parse.c. | ||
32 | AC_DEFUN([gl_PREREQ_PRINTF_PARSE], | ||
33 | [ | ||
34 | AC_REQUIRE([AC_TYPE_LONG_LONG_INT]) | ||
35 | AC_REQUIRE([gt_TYPE_LONGDOUBLE]) | ||
36 | AC_REQUIRE([gt_TYPE_WCHAR_T]) | ||
37 | AC_REQUIRE([gt_TYPE_WINT_T]) | ||
38 | AC_REQUIRE([AC_TYPE_SIZE_T]) | ||
39 | AC_CHECK_TYPES(ptrdiff_t) | ||
40 | AC_REQUIRE([gt_AC_TYPE_INTMAX_T]) | ||
41 | ]) | ||
42 | |||
43 | # Prerequisites of lib/vasnprintf.c. | ||
44 | AC_DEFUN([gl_PREREQ_VASNPRINTF], | ||
45 | [ | ||
46 | AC_REQUIRE([AC_FUNC_ALLOCA]) | ||
47 | AC_REQUIRE([AC_TYPE_LONG_LONG_INT]) | ||
48 | AC_REQUIRE([gt_TYPE_LONGDOUBLE]) | ||
49 | AC_REQUIRE([gt_TYPE_WCHAR_T]) | ||
50 | AC_REQUIRE([gt_TYPE_WINT_T]) | ||
51 | AC_CHECK_FUNCS(snprintf wcslen) | ||
52 | ]) | ||
53 | |||
54 | # Prerequisites of lib/asnprintf.c. | ||
55 | AC_DEFUN([gl_PREREQ_ASNPRINTF], | ||
56 | [ | ||
57 | ]) | ||
diff --git a/gl/m4/vasprintf.m4 b/gl/m4/vasprintf.m4 new file mode 100644 index 00000000..18ca6327 --- /dev/null +++ b/gl/m4/vasprintf.m4 | |||
@@ -0,0 +1,33 @@ | |||
1 | # vasprintf.m4 serial 2 | ||
2 | dnl Copyright (C) 2002-2003, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FUNC_VASPRINTF], | ||
8 | [ | ||
9 | AC_REPLACE_FUNCS(vasprintf) | ||
10 | if test $ac_cv_func_vasprintf = no; then | ||
11 | AC_LIBOBJ(asprintf) | ||
12 | gl_PREREQ_VASPRINTF_H | ||
13 | gl_PREREQ_VASPRINTF | ||
14 | gl_PREREQ_ASPRINTF | ||
15 | fi | ||
16 | ]) | ||
17 | |||
18 | # Prerequisites of lib/vasprintf.h. | ||
19 | AC_DEFUN([gl_PREREQ_VASPRINTF_H], | ||
20 | [ | ||
21 | dnl Persuade glibc <stdio.h> to declare asprintf() and vasprintf(). | ||
22 | AC_REQUIRE([AC_GNU_SOURCE]) | ||
23 | ]) | ||
24 | |||
25 | # Prerequisites of lib/vasprintf.c. | ||
26 | AC_DEFUN([gl_PREREQ_VASPRINTF], | ||
27 | [ | ||
28 | ]) | ||
29 | |||
30 | # Prerequisites of lib/asprintf.c. | ||
31 | AC_DEFUN([gl_PREREQ_ASPRINTF], | ||
32 | [ | ||
33 | ]) | ||
diff --git a/gl/m4/visibility.m4 b/gl/m4/visibility.m4 new file mode 100644 index 00000000..2ff6330a --- /dev/null +++ b/gl/m4/visibility.m4 | |||
@@ -0,0 +1,52 @@ | |||
1 | # visibility.m4 serial 1 (gettext-0.15) | ||
2 | dnl Copyright (C) 2005 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | |||
9 | dnl Tests whether the compiler supports the command-line option | ||
10 | dnl -fvisibility=hidden and the function and variable attributes | ||
11 | dnl __attribute__((__visibility__("hidden"))) and | ||
12 | dnl __attribute__((__visibility__("default"))). | ||
13 | dnl Does *not* test for __visibility__("protected") - which has tricky | ||
14 | dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on | ||
15 | dnl MacOS X. | ||
16 | dnl Does *not* test for __visibility__("internal") - which has processor | ||
17 | dnl dependent semantics. | ||
18 | dnl Does *not* test for #pragma GCC visibility push(hidden) - which is | ||
19 | dnl "really only recommended for legacy code". | ||
20 | dnl Set the variable CFLAG_VISIBILITY. | ||
21 | dnl Defines and sets the variable HAVE_VISIBILITY. | ||
22 | |||
23 | AC_DEFUN([gl_VISIBILITY], | ||
24 | [ | ||
25 | AC_REQUIRE([AC_PROG_CC]) | ||
26 | CFLAG_VISIBILITY= | ||
27 | HAVE_VISIBILITY=0 | ||
28 | if test -n "$GCC"; then | ||
29 | AC_MSG_CHECKING([for simple visibility declarations]) | ||
30 | AC_CACHE_VAL(gl_cv_cc_visibility, [ | ||
31 | gl_save_CFLAGS="$CFLAGS" | ||
32 | CFLAGS="$CFLAGS -fvisibility=hidden" | ||
33 | AC_TRY_COMPILE( | ||
34 | [extern __attribute__((__visibility__("hidden"))) int hiddenvar; | ||
35 | extern __attribute__((__visibility__("default"))) int exportedvar; | ||
36 | extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void); | ||
37 | extern __attribute__((__visibility__("default"))) int exportedfunc (void);], | ||
38 | [], | ||
39 | gl_cv_cc_visibility=yes, | ||
40 | gl_cv_cc_visibility=no) | ||
41 | CFLAGS="$gl_save_CFLAGS"]) | ||
42 | AC_MSG_RESULT([$gl_cv_cc_visibility]) | ||
43 | if test $gl_cv_cc_visibility = yes; then | ||
44 | CFLAG_VISIBILITY="-fvisibility=hidden" | ||
45 | HAVE_VISIBILITY=1 | ||
46 | fi | ||
47 | fi | ||
48 | AC_SUBST([CFLAG_VISIBILITY]) | ||
49 | AC_SUBST([HAVE_VISIBILITY]) | ||
50 | AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY], | ||
51 | [Define to 1 or 0, depending whether the compiler supports simple visibility declarations.]) | ||
52 | ]) | ||
diff --git a/gl/m4/vsnprintf.m4 b/gl/m4/vsnprintf.m4 new file mode 100644 index 00000000..cb8a9b18 --- /dev/null +++ b/gl/m4/vsnprintf.m4 | |||
@@ -0,0 +1,15 @@ | |||
1 | # vsnprintf.m4 serial 2 | ||
2 | dnl Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FUNC_VSNPRINTF], | ||
8 | [ | ||
9 | AC_REPLACE_FUNCS(vsnprintf) | ||
10 | AC_CHECK_DECLS_ONCE(vsnprintf) | ||
11 | gl_PREREQ_VSNPRINTF | ||
12 | ]) | ||
13 | |||
14 | # Prerequisites of lib/vsnprintf.c. | ||
15 | AC_DEFUN([gl_PREREQ_VSNPRINTF], [:]) | ||
diff --git a/gl/m4/wchar.m4 b/gl/m4/wchar.m4 new file mode 100644 index 00000000..068f22d3 --- /dev/null +++ b/gl/m4/wchar.m4 | |||
@@ -0,0 +1,29 @@ | |||
1 | dnl A placeholder for ISO C99 <wchar.h>, for platforms that have issues. | ||
2 | |||
3 | dnl Copyright (C) 2007 Free Software Foundation, Inc. | ||
4 | dnl This file is free software; the Free Software Foundation | ||
5 | dnl gives unlimited permission to copy and/or distribute it, | ||
6 | dnl with or without modifications, as long as this notice is preserved. | ||
7 | |||
8 | dnl Written by Eric Blake. | ||
9 | |||
10 | # wchar.m4 serial 1 | ||
11 | |||
12 | AC_DEFUN([gl_WCHAR_H], | ||
13 | [ | ||
14 | AC_CACHE_CHECK([whether <wchar.h> is standalone], | ||
15 | [gl_cv_header_wchar_h_standalone], | ||
16 | [AC_COMPILE_IFELSE([[#include <wchar.h> | ||
17 | wchar_t w;]], | ||
18 | [gl_cv_header_wchar_h_standalone=yes], | ||
19 | [gl_cv_header_wchar_h_standalone=no])]) | ||
20 | if test $gl_cv_header_wchar_h_standalone = yes; then | ||
21 | WCHAR_H= | ||
22 | else | ||
23 | gl_ABSOLUTE_HEADER([wchar.h]) | ||
24 | ABSOLUTE_WCHAR_H=\"$gl_cv_absolute_wchar_h\" | ||
25 | WCHAR_H=wchar.h | ||
26 | fi | ||
27 | AC_SUBST([ABSOLUTE_WCHAR_H]) | ||
28 | AC_SUBST([WCHAR_H]) | ||
29 | ]) | ||
diff --git a/gl/m4/wchar_t.m4 b/gl/m4/wchar_t.m4 new file mode 100644 index 00000000..cde2129a --- /dev/null +++ b/gl/m4/wchar_t.m4 | |||
@@ -0,0 +1,20 @@ | |||
1 | # wchar_t.m4 serial 1 (gettext-0.12) | ||
2 | dnl Copyright (C) 2002-2003 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | dnl Test whether <stddef.h> has the 'wchar_t' type. | ||
9 | dnl Prerequisite: AC_PROG_CC | ||
10 | |||
11 | AC_DEFUN([gt_TYPE_WCHAR_T], | ||
12 | [ | ||
13 | AC_CACHE_CHECK([for wchar_t], gt_cv_c_wchar_t, | ||
14 | [AC_TRY_COMPILE([#include <stddef.h> | ||
15 | wchar_t foo = (wchar_t)'\0';], , | ||
16 | gt_cv_c_wchar_t=yes, gt_cv_c_wchar_t=no)]) | ||
17 | if test $gt_cv_c_wchar_t = yes; then | ||
18 | AC_DEFINE(HAVE_WCHAR_T, 1, [Define if you have the 'wchar_t' type.]) | ||
19 | fi | ||
20 | ]) | ||
diff --git a/gl/m4/wctype.m4 b/gl/m4/wctype.m4 new file mode 100644 index 00000000..62994c62 --- /dev/null +++ b/gl/m4/wctype.m4 | |||
@@ -0,0 +1,41 @@ | |||
1 | dnl A placeholder for ISO C99 <wctype.h>, for platforms that lack it. | ||
2 | |||
3 | dnl Copyright (C) 2006, 2007 Free Software Foundation, Inc. | ||
4 | dnl This file is free software; the Free Software Foundation | ||
5 | dnl gives unlimited permission to copy and/or distribute it, | ||
6 | dnl with or without modifications, as long as this notice is preserved. | ||
7 | |||
8 | dnl Written by Paul Eggert. | ||
9 | |||
10 | AC_DEFUN([gl_WCTYPE_H], | ||
11 | [ | ||
12 | AC_CHECK_FUNCS_ONCE([iswcntrl]) | ||
13 | AC_CHECK_HEADERS_ONCE([wctype.h]) | ||
14 | AC_REQUIRE([AC_C_INLINE]) | ||
15 | |||
16 | AC_REQUIRE([gt_TYPE_WINT_T]) | ||
17 | if test $gt_cv_c_wint_t = yes; then | ||
18 | HAVE_WINT_T=1 | ||
19 | else | ||
20 | HAVE_WINT_T=0 | ||
21 | fi | ||
22 | AC_SUBST([HAVE_WINT_T]) | ||
23 | |||
24 | WCTYPE_H=wctype.h | ||
25 | if test $ac_cv_header_wctype_h = yes; then | ||
26 | if test "$ac_cv_func_iswcntrl" = yes; then | ||
27 | WCTYPE_H= | ||
28 | fi | ||
29 | dnl Compute ABSOLUTE_WCTYPE_H even if WCTYPE_H is empty, | ||
30 | dnl for the benefit of builds from non-distclean directories. | ||
31 | gl_ABSOLUTE_HEADER([wctype.h]) | ||
32 | ABSOLUTE_WCTYPE_H=\"$gl_cv_absolute_wctype_h\" | ||
33 | HAVE_WCTYPE_H=1 | ||
34 | else | ||
35 | ABSOLUTE_WCTYPE_H=\"no/such/file/wctype.h\" | ||
36 | HAVE_WCTYPE_H=0 | ||
37 | fi | ||
38 | AC_SUBST([ABSOLUTE_WCTYPE_H]) | ||
39 | AC_SUBST([HAVE_WCTYPE_H]) | ||
40 | AC_SUBST([WCTYPE_H]) | ||
41 | ]) | ||
diff --git a/gl/m4/wcwidth.m4 b/gl/m4/wcwidth.m4 new file mode 100644 index 00000000..b4834991 --- /dev/null +++ b/gl/m4/wcwidth.m4 | |||
@@ -0,0 +1,30 @@ | |||
1 | # wcwidth.m4 serial 8 | ||
2 | dnl Copyright (C) 2006, 2007 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_FUNC_WCWIDTH], | ||
8 | [ | ||
9 | dnl Persuade glibc <wchar.h> to declare wcwidth(). | ||
10 | AC_REQUIRE([AC_GNU_SOURCE]) | ||
11 | |||
12 | AC_REQUIRE([AC_C_INLINE]) | ||
13 | AC_REQUIRE([gt_TYPE_WCHAR_T]) | ||
14 | AC_REQUIRE([gt_TYPE_WINT_T]) | ||
15 | |||
16 | AC_CHECK_HEADERS_ONCE([wchar.h]) | ||
17 | AC_CHECK_FUNCS_ONCE([wcwidth]) | ||
18 | |||
19 | AC_CHECK_DECLS([wcwidth], [], [], [ | ||
20 | /* AIX 3.2.5 declares wcwidth in <string.h>. */ | ||
21 | #include <string.h> | ||
22 | /* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before | ||
23 | <wchar.h>. | ||
24 | BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be included | ||
25 | before <wchar.h>. */ | ||
26 | #include <stddef.h> | ||
27 | #include <stdio.h> | ||
28 | #include <time.h> | ||
29 | #include <wchar.h> | ||
30 | ])]) | ||
diff --git a/gl/m4/wint_t.m4 b/gl/m4/wint_t.m4 new file mode 100644 index 00000000..3706c047 --- /dev/null +++ b/gl/m4/wint_t.m4 | |||
@@ -0,0 +1,28 @@ | |||
1 | # wint_t.m4 serial 2 (gettext-0.12) | ||
2 | dnl Copyright (C) 2003, 2007 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | dnl From Bruno Haible. | ||
8 | dnl Test whether <wchar.h> has the 'wint_t' type. | ||
9 | dnl Prerequisite: AC_PROG_CC | ||
10 | |||
11 | AC_DEFUN([gt_TYPE_WINT_T], | ||
12 | [ | ||
13 | AC_CACHE_CHECK([for wint_t], gt_cv_c_wint_t, | ||
14 | [AC_TRY_COMPILE([ | ||
15 | /* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before | ||
16 | <wchar.h>. | ||
17 | BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be included | ||
18 | before <wchar.h>. */ | ||
19 | #include <stddef.h> | ||
20 | #include <stdio.h> | ||
21 | #include <time.h> | ||
22 | #include <wchar.h> | ||
23 | wint_t foo = (wchar_t)'\0';], , | ||
24 | gt_cv_c_wint_t=yes, gt_cv_c_wint_t=no)]) | ||
25 | if test $gt_cv_c_wint_t = yes; then | ||
26 | AC_DEFINE(HAVE_WINT_T, 1, [Define if you have the 'wint_t' type.]) | ||
27 | fi | ||
28 | ]) | ||
diff --git a/gl/m4/xalloc.m4 b/gl/m4/xalloc.m4 new file mode 100644 index 00000000..837a948c --- /dev/null +++ b/gl/m4/xalloc.m4 | |||
@@ -0,0 +1,24 @@ | |||
1 | # xalloc.m4 serial 16 | ||
2 | dnl Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_XALLOC], | ||
8 | [ | ||
9 | AC_LIBOBJ([xmalloc]) | ||
10 | |||
11 | gl_PREREQ_XALLOC | ||
12 | gl_PREREQ_XMALLOC | ||
13 | ]) | ||
14 | |||
15 | # Prerequisites of lib/xalloc.h. | ||
16 | AC_DEFUN([gl_PREREQ_XALLOC], [ | ||
17 | AC_REQUIRE([gl_INLINE]) | ||
18 | : | ||
19 | ]) | ||
20 | |||
21 | # Prerequisites of lib/xmalloc.c. | ||
22 | AC_DEFUN([gl_PREREQ_XMALLOC], [ | ||
23 | : | ||
24 | ]) | ||
diff --git a/gl/m4/xsize.m4 b/gl/m4/xsize.m4 new file mode 100644 index 00000000..85bb721e --- /dev/null +++ b/gl/m4/xsize.m4 | |||
@@ -0,0 +1,13 @@ | |||
1 | # xsize.m4 serial 3 | ||
2 | dnl Copyright (C) 2003-2004 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_XSIZE], | ||
8 | [ | ||
9 | dnl Prerequisites of lib/xsize.h. | ||
10 | AC_REQUIRE([gl_SIZE_MAX]) | ||
11 | AC_REQUIRE([AC_C_INLINE]) | ||
12 | AC_CHECK_HEADERS(stdint.h) | ||
13 | ]) | ||
diff --git a/gl/m4/xstrndup.m4 b/gl/m4/xstrndup.m4 new file mode 100644 index 00000000..8a30ab15 --- /dev/null +++ b/gl/m4/xstrndup.m4 | |||
@@ -0,0 +1,15 @@ | |||
1 | # xstrndup.m4 serial 2 | ||
2 | dnl Copyright (C) 2003 Free Software Foundation, Inc. | ||
3 | dnl This file is free software; the Free Software Foundation | ||
4 | dnl gives unlimited permission to copy and/or distribute it, | ||
5 | dnl with or without modifications, as long as this notice is preserved. | ||
6 | |||
7 | AC_DEFUN([gl_XSTRNDUP], | ||
8 | [ | ||
9 | gl_PREREQ_XSTRNDUP | ||
10 | ]) | ||
11 | |||
12 | # Prerequisites of lib/xstrndup.c. | ||
13 | AC_DEFUN([gl_PREREQ_XSTRNDUP], [ | ||
14 | : | ||
15 | ]) | ||
diff --git a/gl/malloc.c b/gl/malloc.c new file mode 100644 index 00000000..d4dae3e1 --- /dev/null +++ b/gl/malloc.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* malloc() function that is glibc compatible. | ||
2 | |||
3 | Copyright (C) 1997, 1998, 2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* written by Jim Meyering */ | ||
20 | |||
21 | #include <config.h> | ||
22 | #undef malloc | ||
23 | |||
24 | #include <stdlib.h> | ||
25 | |||
26 | /* Allocate an N-byte block of memory from the heap. | ||
27 | If N is zero, allocate a 1-byte block. */ | ||
28 | |||
29 | void * | ||
30 | rpl_malloc (size_t n) | ||
31 | { | ||
32 | if (n == 0) | ||
33 | n = 1; | ||
34 | return malloc (n); | ||
35 | } | ||
diff --git a/gl/mbchar.c b/gl/mbchar.c new file mode 100644 index 00000000..95373f58 --- /dev/null +++ b/gl/mbchar.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* Copyright (C) 2001, 2006 Free Software Foundation, Inc. | ||
2 | |||
3 | This program is free software; you can redistribute it and/or modify | ||
4 | it under the terms of the GNU General Public License as published by | ||
5 | the Free Software Foundation; either version 2, or (at your option) | ||
6 | any later version. | ||
7 | |||
8 | This program is distributed in the hope that it will be useful, | ||
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | GNU General Public License for more details. | ||
12 | |||
13 | You should have received a copy of the GNU General Public License | ||
14 | along with this program; if not, write to the Free Software Foundation, | ||
15 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
16 | |||
17 | |||
18 | #include <config.h> | ||
19 | |||
20 | #include <limits.h> | ||
21 | |||
22 | #include "mbchar.h" | ||
23 | |||
24 | #if IS_BASIC_ASCII | ||
25 | |||
26 | /* Bit table of characters in the ISO C "basic character set". */ | ||
27 | const unsigned int is_basic_table [UCHAR_MAX / 32 + 1] = | ||
28 | { | ||
29 | 0x00001a00, /* '\t' '\v' '\f' */ | ||
30 | 0xffffffef, /* ' '...'#' '%'...'?' */ | ||
31 | 0xfffffffe, /* 'A'...'Z' '[' '\\' ']' '^' '_' */ | ||
32 | 0x7ffffffe /* 'a'...'z' '{' '|' '}' '~' */ | ||
33 | /* The remaining bits are 0. */ | ||
34 | }; | ||
35 | |||
36 | #endif /* IS_BASIC_ASCII */ | ||
diff --git a/gl/mbchar.h b/gl/mbchar.h new file mode 100644 index 00000000..f3e28ef5 --- /dev/null +++ b/gl/mbchar.h | |||
@@ -0,0 +1,353 @@ | |||
1 | /* Multibyte character data type. | ||
2 | Copyright (C) 2001, 2005-2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
17 | |||
18 | /* Written by Bruno Haible <bruno@clisp.org>. */ | ||
19 | |||
20 | /* A multibyte character is a short subsequence of a char* string, | ||
21 | representing a single wide character. | ||
22 | |||
23 | We use multibyte characters instead of wide characters because of | ||
24 | the following goals: | ||
25 | 1) correct multibyte handling, i.e. operate according to the LC_CTYPE | ||
26 | locale, | ||
27 | 2) ease of maintenance, i.e. the maintainer needs not know all details | ||
28 | of the ISO C 99 standard, | ||
29 | 3) don't fail grossly if the input is not in the encoding set by the | ||
30 | locale, because often different encodings are in use in the same | ||
31 | countries (ISO-8859-1/UTF-8, EUC-JP/Shift_JIS, ...), | ||
32 | 4) fast in the case of ASCII characters, | ||
33 | 5) portability, i.e. don't make unportable assumptions about wchar_t. | ||
34 | |||
35 | Multibyte characters are only accessed through the mb* macros. | ||
36 | |||
37 | mb_ptr (mbc) | ||
38 | return a pointer to the beginning of the multibyte sequence. | ||
39 | |||
40 | mb_len (mbc) | ||
41 | returns the number of bytes occupied by the multibyte sequence. | ||
42 | Always > 0. | ||
43 | |||
44 | mb_iseq (mbc, sc) | ||
45 | returns true if mbc is the standard ASCII character sc. | ||
46 | |||
47 | mb_isnul (mbc) | ||
48 | returns true if mbc is the nul character. | ||
49 | |||
50 | mb_cmp (mbc1, mbc2) | ||
51 | returns a positive, zero, or negative value depending on whether mbc1 | ||
52 | sorts after, same or before mbc2. | ||
53 | |||
54 | mb_casecmp (mbc1, mbc2) | ||
55 | returns a positive, zero, or negative value depending on whether mbc1 | ||
56 | sorts after, same or before mbc2, modulo upper/lowercase conversion. | ||
57 | |||
58 | mb_equal (mbc1, mbc2) | ||
59 | returns true if mbc1 and mbc2 are equal. | ||
60 | |||
61 | mb_caseequal (mbc1, mbc2) | ||
62 | returns true if mbc1 and mbc2 are equal modulo upper/lowercase conversion. | ||
63 | |||
64 | mb_isalnum (mbc) | ||
65 | returns true if mbc is alphanumeric. | ||
66 | |||
67 | mb_isalpha (mbc) | ||
68 | returns true if mbc is alphabetic. | ||
69 | |||
70 | mb_isascii(mbc) | ||
71 | returns true if mbc is plain ASCII. | ||
72 | |||
73 | mb_isblank (mbc) | ||
74 | returns true if mbc is a blank. | ||
75 | |||
76 | mb_iscntrl (mbc) | ||
77 | returns true if mbc is a control character. | ||
78 | |||
79 | mb_isdigit (mbc) | ||
80 | returns true if mbc is a decimal digit. | ||
81 | |||
82 | mb_isgraph (mbc) | ||
83 | returns true if mbc is a graphic character. | ||
84 | |||
85 | mb_islower (mbc) | ||
86 | returns true if mbc is lowercase. | ||
87 | |||
88 | mb_isprint (mbc) | ||
89 | returns true if mbc is a printable character. | ||
90 | |||
91 | mb_ispunct (mbc) | ||
92 | returns true if mbc is a punctuation character. | ||
93 | |||
94 | mb_isspace (mbc) | ||
95 | returns true if mbc is a space character. | ||
96 | |||
97 | mb_isupper (mbc) | ||
98 | returns true if mbc is uppercase. | ||
99 | |||
100 | mb_isxdigit (mbc) | ||
101 | returns true if mbc is a hexadecimal digit. | ||
102 | |||
103 | mb_width (mbc) | ||
104 | returns the number of columns on the output device occupied by mbc. | ||
105 | Always >= 0. | ||
106 | |||
107 | mb_putc (mbc, stream) | ||
108 | outputs mbc on stream, a byte oriented FILE stream opened for output. | ||
109 | |||
110 | mb_setascii (&mbc, sc) | ||
111 | assigns the standard ASCII character sc to mbc. | ||
112 | |||
113 | mb_copy (&destmbc, &srcmbc) | ||
114 | copies srcmbc to destmbc. | ||
115 | |||
116 | Here are the function prototypes of the macros. | ||
117 | |||
118 | extern const char * mb_ptr (const mbchar_t mbc); | ||
119 | extern size_t mb_len (const mbchar_t mbc); | ||
120 | extern bool mb_iseq (const mbchar_t mbc, char sc); | ||
121 | extern bool mb_isnul (const mbchar_t mbc); | ||
122 | extern int mb_cmp (const mbchar_t mbc1, const mbchar_t mbc2); | ||
123 | extern int mb_casecmp (const mbchar_t mbc1, const mbchar_t mbc2); | ||
124 | extern bool mb_equal (const mbchar_t mbc1, const mbchar_t mbc2); | ||
125 | extern bool mb_caseequal (const mbchar_t mbc1, const mbchar_t mbc2); | ||
126 | extern bool mb_isalnum (const mbchar_t mbc); | ||
127 | extern bool mb_isalpha (const mbchar_t mbc); | ||
128 | extern bool mb_isascii (const mbchar_t mbc); | ||
129 | extern bool mb_isblank (const mbchar_t mbc); | ||
130 | extern bool mb_iscntrl (const mbchar_t mbc); | ||
131 | extern bool mb_isdigit (const mbchar_t mbc); | ||
132 | extern bool mb_isgraph (const mbchar_t mbc); | ||
133 | extern bool mb_islower (const mbchar_t mbc); | ||
134 | extern bool mb_isprint (const mbchar_t mbc); | ||
135 | extern bool mb_ispunct (const mbchar_t mbc); | ||
136 | extern bool mb_isspace (const mbchar_t mbc); | ||
137 | extern bool mb_isupper (const mbchar_t mbc); | ||
138 | extern bool mb_isxdigit (const mbchar_t mbc); | ||
139 | extern int mb_width (const mbchar_t mbc); | ||
140 | extern void mb_putc (const mbchar_t mbc, FILE *stream); | ||
141 | extern void mb_setascii (mbchar_t *new, char sc); | ||
142 | extern void mb_copy (mbchar_t *new, const mbchar_t *old); | ||
143 | */ | ||
144 | |||
145 | #ifndef _MBCHAR_H | ||
146 | #define _MBCHAR_H 1 | ||
147 | |||
148 | #include <stdbool.h> | ||
149 | #include <string.h> | ||
150 | |||
151 | /* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before | ||
152 | <wchar.h>. | ||
153 | BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before | ||
154 | <wchar.h>. */ | ||
155 | #include <stdio.h> | ||
156 | #include <time.h> | ||
157 | #include <wchar.h> | ||
158 | #include <wctype.h> | ||
159 | |||
160 | #include "wcwidth.h" | ||
161 | |||
162 | #define MBCHAR_BUF_SIZE 24 | ||
163 | |||
164 | struct mbchar | ||
165 | { | ||
166 | const char *ptr; /* pointer to current character */ | ||
167 | size_t bytes; /* number of bytes of current character, > 0 */ | ||
168 | bool wc_valid; /* true if wc is a valid wide character */ | ||
169 | wchar_t wc; /* if wc_valid: the current character */ | ||
170 | char buf[MBCHAR_BUF_SIZE]; /* room for the bytes, used for file input only */ | ||
171 | }; | ||
172 | |||
173 | /* EOF (not a real character) is represented with bytes = 0 and | ||
174 | wc_valid = false. */ | ||
175 | |||
176 | typedef struct mbchar mbchar_t; | ||
177 | |||
178 | /* Access the current character. */ | ||
179 | #define mb_ptr(mbc) ((mbc).ptr) | ||
180 | #define mb_len(mbc) ((mbc).bytes) | ||
181 | |||
182 | /* Comparison of characters. */ | ||
183 | #define mb_iseq(mbc, sc) ((mbc).wc_valid && (mbc).wc == (sc)) | ||
184 | #define mb_isnul(mbc) ((mbc).wc_valid && (mbc).wc == 0) | ||
185 | #define mb_cmp(mbc1, mbc2) \ | ||
186 | ((mbc1).wc_valid \ | ||
187 | ? ((mbc2).wc_valid \ | ||
188 | ? (int) (mbc1).wc - (int) (mbc2).wc \ | ||
189 | : -1) \ | ||
190 | : ((mbc2).wc_valid \ | ||
191 | ? 1 \ | ||
192 | : (mbc1).bytes == (mbc2).bytes \ | ||
193 | ? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \ | ||
194 | : (mbc1).bytes < (mbc2).bytes \ | ||
195 | ? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \ | ||
196 | : (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1))) | ||
197 | #define mb_casecmp(mbc1, mbc2) \ | ||
198 | ((mbc1).wc_valid \ | ||
199 | ? ((mbc2).wc_valid \ | ||
200 | ? (int) towlower ((mbc1).wc) - (int) towlower ((mbc2).wc) \ | ||
201 | : -1) \ | ||
202 | : ((mbc2).wc_valid \ | ||
203 | ? 1 \ | ||
204 | : (mbc1).bytes == (mbc2).bytes \ | ||
205 | ? memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) \ | ||
206 | : (mbc1).bytes < (mbc2).bytes \ | ||
207 | ? (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) > 0 ? 1 : -1) \ | ||
208 | : (memcmp ((mbc1).ptr, (mbc2).ptr, (mbc2).bytes) >= 0 ? 1 : -1))) | ||
209 | #define mb_equal(mbc1, mbc2) \ | ||
210 | ((mbc1).wc_valid && (mbc2).wc_valid \ | ||
211 | ? (mbc1).wc == (mbc2).wc \ | ||
212 | : (mbc1).bytes == (mbc2).bytes \ | ||
213 | && memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0) | ||
214 | #define mb_caseequal(mbc1, mbc2) \ | ||
215 | ((mbc1).wc_valid && (mbc2).wc_valid \ | ||
216 | ? towlower ((mbc1).wc) == towlower ((mbc2).wc) \ | ||
217 | : (mbc1).bytes == (mbc2).bytes \ | ||
218 | && memcmp ((mbc1).ptr, (mbc2).ptr, (mbc1).bytes) == 0) | ||
219 | |||
220 | /* <ctype.h>, <wctype.h> classification. */ | ||
221 | #define mb_isascii(mbc) \ | ||
222 | ((mbc).wc_valid && (mbc).wc >= 0 && (mbc).wc <= 127) | ||
223 | #define mb_isalnum(mbc) ((mbc).wc_valid && iswalnum ((mbc).wc)) | ||
224 | #define mb_isalpha(mbc) ((mbc).wc_valid && iswalpha ((mbc).wc)) | ||
225 | #define mb_isblank(mbc) ((mbc).wc_valid && iswblank ((mbc).wc)) | ||
226 | #define mb_iscntrl(mbc) ((mbc).wc_valid && iswcntrl ((mbc).wc)) | ||
227 | #define mb_isdigit(mbc) ((mbc).wc_valid && iswdigit ((mbc).wc)) | ||
228 | #define mb_isgraph(mbc) ((mbc).wc_valid && iswgraph ((mbc).wc)) | ||
229 | #define mb_islower(mbc) ((mbc).wc_valid && iswlower ((mbc).wc)) | ||
230 | #define mb_isprint(mbc) ((mbc).wc_valid && iswprint ((mbc).wc)) | ||
231 | #define mb_ispunct(mbc) ((mbc).wc_valid && iswpunct ((mbc).wc)) | ||
232 | #define mb_isspace(mbc) ((mbc).wc_valid && iswspace ((mbc).wc)) | ||
233 | #define mb_isupper(mbc) ((mbc).wc_valid && iswupper ((mbc).wc)) | ||
234 | #define mb_isxdigit(mbc) ((mbc).wc_valid && iswxdigit ((mbc).wc)) | ||
235 | |||
236 | /* Extra <wchar.h> function. */ | ||
237 | |||
238 | /* Unprintable characters appear as a small box of width 1. */ | ||
239 | #define MB_UNPRINTABLE_WIDTH 1 | ||
240 | |||
241 | static inline int | ||
242 | mb_width_aux (wint_t wc) | ||
243 | { | ||
244 | int w = wcwidth (wc); | ||
245 | /* For unprintable characters, arbitrarily return 0 for control characters | ||
246 | and MB_UNPRINTABLE_WIDTH otherwise. */ | ||
247 | return (w >= 0 ? w : iswcntrl (wc) ? 0 : MB_UNPRINTABLE_WIDTH); | ||
248 | } | ||
249 | |||
250 | #define mb_width(mbc) \ | ||
251 | ((mbc).wc_valid ? mb_width_aux ((mbc).wc) : MB_UNPRINTABLE_WIDTH) | ||
252 | |||
253 | /* Output. */ | ||
254 | #define mb_putc(mbc, stream) fwrite ((mbc).ptr, 1, (mbc).bytes, (stream)) | ||
255 | |||
256 | /* Assignment. */ | ||
257 | #define mb_setascii(mbc, sc) \ | ||
258 | ((mbc)->ptr = (mbc)->buf, (mbc)->bytes = 1, (mbc)->wc_valid = 1, \ | ||
259 | (mbc)->wc = (mbc)->buf[0] = (sc)) | ||
260 | |||
261 | /* Copying a character. */ | ||
262 | static inline void | ||
263 | mb_copy (mbchar_t *new_mbc, const mbchar_t *old_mbc) | ||
264 | { | ||
265 | if (old_mbc->ptr == &old_mbc->buf[0]) | ||
266 | { | ||
267 | memcpy (&new_mbc->buf[0], &old_mbc->buf[0], old_mbc->bytes); | ||
268 | new_mbc->ptr = &new_mbc->buf[0]; | ||
269 | } | ||
270 | else | ||
271 | new_mbc->ptr = old_mbc->ptr; | ||
272 | new_mbc->bytes = old_mbc->bytes; | ||
273 | if ((new_mbc->wc_valid = old_mbc->wc_valid)) | ||
274 | new_mbc->wc = old_mbc->wc; | ||
275 | } | ||
276 | |||
277 | |||
278 | /* is_basic(c) tests whether the single-byte character c is in the | ||
279 | ISO C "basic character set". | ||
280 | This is a convenience function, and is in this file only to share code | ||
281 | between mbiter_multi.h and mbfile_multi.h. */ | ||
282 | #if (' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ | ||
283 | && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ | ||
284 | && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ | ||
285 | && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ | ||
286 | && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ | ||
287 | && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ | ||
288 | && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ | ||
289 | && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ | ||
290 | && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ | ||
291 | && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ | ||
292 | && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ | ||
293 | && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ | ||
294 | && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ | ||
295 | && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ | ||
296 | && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ | ||
297 | && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ | ||
298 | && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ | ||
299 | && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ | ||
300 | && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ | ||
301 | && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ | ||
302 | && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ | ||
303 | && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ | ||
304 | && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126) | ||
305 | /* The character set is ISO-646, not EBCDIC. */ | ||
306 | # define IS_BASIC_ASCII 1 | ||
307 | |||
308 | extern const unsigned int is_basic_table[]; | ||
309 | |||
310 | static inline bool | ||
311 | is_basic (char c) | ||
312 | { | ||
313 | return (is_basic_table [(unsigned char) c >> 5] >> ((unsigned char) c & 31)) | ||
314 | & 1; | ||
315 | } | ||
316 | |||
317 | #else | ||
318 | |||
319 | static inline bool | ||
320 | is_basic (char c) | ||
321 | { | ||
322 | switch (c) | ||
323 | { | ||
324 | case '\t': case '\v': case '\f': | ||
325 | case ' ': case '!': case '"': case '#': case '%': | ||
326 | case '&': case '\'': case '(': case ')': case '*': | ||
327 | case '+': case ',': case '-': case '.': case '/': | ||
328 | case '0': case '1': case '2': case '3': case '4': | ||
329 | case '5': case '6': case '7': case '8': case '9': | ||
330 | case ':': case ';': case '<': case '=': case '>': | ||
331 | case '?': | ||
332 | case 'A': case 'B': case 'C': case 'D': case 'E': | ||
333 | case 'F': case 'G': case 'H': case 'I': case 'J': | ||
334 | case 'K': case 'L': case 'M': case 'N': case 'O': | ||
335 | case 'P': case 'Q': case 'R': case 'S': case 'T': | ||
336 | case 'U': case 'V': case 'W': case 'X': case 'Y': | ||
337 | case 'Z': | ||
338 | case '[': case '\\': case ']': case '^': case '_': | ||
339 | case 'a': case 'b': case 'c': case 'd': case 'e': | ||
340 | case 'f': case 'g': case 'h': case 'i': case 'j': | ||
341 | case 'k': case 'l': case 'm': case 'n': case 'o': | ||
342 | case 'p': case 'q': case 'r': case 's': case 't': | ||
343 | case 'u': case 'v': case 'w': case 'x': case 'y': | ||
344 | case 'z': case '{': case '|': case '}': case '~': | ||
345 | return 1; | ||
346 | default: | ||
347 | return 0; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | #endif | ||
352 | |||
353 | #endif /* _MBCHAR_H */ | ||
diff --git a/gl/mbuiter.h b/gl/mbuiter.h new file mode 100644 index 00000000..9da3a6c7 --- /dev/null +++ b/gl/mbuiter.h | |||
@@ -0,0 +1,203 @@ | |||
1 | /* Iterating through multibyte strings: macros for multi-byte encodings. | ||
2 | Copyright (C) 2001, 2005 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
17 | |||
18 | /* Written by Bruno Haible <bruno@clisp.org>. */ | ||
19 | |||
20 | /* The macros in this file implement forward iteration through a | ||
21 | multi-byte string, without knowing its length a-priori. | ||
22 | |||
23 | With these macros, an iteration loop that looks like | ||
24 | |||
25 | char *iter; | ||
26 | for (iter = buf; *iter != '\0'; iter++) | ||
27 | { | ||
28 | do_something (*iter); | ||
29 | } | ||
30 | |||
31 | becomes | ||
32 | |||
33 | mbui_iterator_t iter; | ||
34 | for (mbui_init (iter, buf); mbui_avail (iter); mbui_advance (iter)) | ||
35 | { | ||
36 | do_something (mbui_cur_ptr (iter), mb_len (mbui_cur (iter))); | ||
37 | } | ||
38 | |||
39 | The benefit of these macros over plain use of mbrtowc is: | ||
40 | - Handling of invalid multibyte sequences is possible without | ||
41 | making the code more complicated, while still preserving the | ||
42 | invalid multibyte sequences. | ||
43 | |||
44 | Compared to mbiter.h, the macros here don't need to know the string's | ||
45 | length a-priori. The downside is that at each step, the look-ahead | ||
46 | that guards against overrunning the terminating '\0' is more expensive. | ||
47 | The mbui_* macros are therefore suitable when there is a high probability | ||
48 | that only the first few multibyte characters need to be inspected. | ||
49 | Whereas the mbi_* macros are better if usually the iteration runs | ||
50 | through the entire string. | ||
51 | |||
52 | mbui_iterator_t | ||
53 | is a type usable for variable declarations. | ||
54 | |||
55 | mbui_init (iter, startptr) | ||
56 | initializes the iterator, starting at startptr. | ||
57 | |||
58 | mbui_avail (iter) | ||
59 | returns true if there are more multibyte chracters available before | ||
60 | the end of string is reached. In this case, mbui_cur (iter) is | ||
61 | initialized to the next multibyte chracter. | ||
62 | |||
63 | mbui_advance (iter) | ||
64 | advances the iterator by one multibyte character. | ||
65 | |||
66 | mbui_cur (iter) | ||
67 | returns the current multibyte character, of type mbchar_t. All the | ||
68 | macros defined in mbchar.h can be used on it. | ||
69 | |||
70 | mbui_cur_ptr (iter) | ||
71 | return a pointer to the beginning of the current multibyte character. | ||
72 | |||
73 | mbui_reloc (iter, ptrdiff) | ||
74 | relocates iterator when the string is moved by ptrdiff bytes. | ||
75 | |||
76 | Here are the function prototypes of the macros. | ||
77 | |||
78 | extern void mbui_init (mbui_iterator_t iter, const char *startptr); | ||
79 | extern bool mbui_avail (mbui_iterator_t iter); | ||
80 | extern void mbui_advance (mbui_iterator_t iter); | ||
81 | extern mbchar_t mbui_cur (mbui_iterator_t iter); | ||
82 | extern const char * mbui_cur_ptr (mbui_iterator_t iter); | ||
83 | extern void mbui_reloc (mbui_iterator_t iter, ptrdiff_t ptrdiff); | ||
84 | */ | ||
85 | |||
86 | #ifndef _MBUITER_H | ||
87 | #define _MBUITER_H 1 | ||
88 | |||
89 | #include <assert.h> | ||
90 | #include <stdbool.h> | ||
91 | #include <stdlib.h> | ||
92 | |||
93 | /* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before | ||
94 | <wchar.h>. | ||
95 | BSD/OS 4.1 has a bug: <stdio.h> and <time.h> must be included before | ||
96 | <wchar.h>. */ | ||
97 | #include <stdio.h> | ||
98 | #include <time.h> | ||
99 | #include <wchar.h> | ||
100 | |||
101 | #include "mbchar.h" | ||
102 | #include "strnlen1.h" | ||
103 | |||
104 | struct mbuiter_multi | ||
105 | { | ||
106 | bool in_shift; /* true if next byte may not be interpreted as ASCII */ | ||
107 | mbstate_t state; /* if in_shift: current shift state */ | ||
108 | bool next_done; /* true if mbui_avail has already filled the following */ | ||
109 | struct mbchar cur; /* the current character: | ||
110 | const char *cur.ptr pointer to current character | ||
111 | The following are only valid after mbui_avail. | ||
112 | size_t cur.bytes number of bytes of current character | ||
113 | bool cur.wc_valid true if wc is a valid wide character | ||
114 | wchar_t cur.wc if wc_valid: the current character | ||
115 | */ | ||
116 | }; | ||
117 | |||
118 | static inline void | ||
119 | mbuiter_multi_next (struct mbuiter_multi *iter) | ||
120 | { | ||
121 | if (iter->next_done) | ||
122 | return; | ||
123 | if (iter->in_shift) | ||
124 | goto with_shift; | ||
125 | /* Handle most ASCII characters quickly, without calling mbrtowc(). */ | ||
126 | if (is_basic (*iter->cur.ptr)) | ||
127 | { | ||
128 | /* These characters are part of the basic character set. ISO C 99 | ||
129 | guarantees that their wide character code is identical to their | ||
130 | char code. */ | ||
131 | iter->cur.bytes = 1; | ||
132 | iter->cur.wc = *iter->cur.ptr; | ||
133 | iter->cur.wc_valid = true; | ||
134 | } | ||
135 | else | ||
136 | { | ||
137 | assert (mbsinit (&iter->state)); | ||
138 | iter->in_shift = true; | ||
139 | with_shift: | ||
140 | iter->cur.bytes = mbrtowc (&iter->cur.wc, iter->cur.ptr, | ||
141 | strnlen1 (iter->cur.ptr, MB_CUR_MAX), | ||
142 | &iter->state); | ||
143 | if (iter->cur.bytes == (size_t) -1) | ||
144 | { | ||
145 | /* An invalid multibyte sequence was encountered. */ | ||
146 | iter->cur.bytes = 1; | ||
147 | iter->cur.wc_valid = false; | ||
148 | /* Whether to set iter->in_shift = false and reset iter->state | ||
149 | or not is not very important; the string is bogus anyway. */ | ||
150 | } | ||
151 | else if (iter->cur.bytes == (size_t) -2) | ||
152 | { | ||
153 | /* An incomplete multibyte character at the end. */ | ||
154 | iter->cur.bytes = strlen (iter->cur.ptr); | ||
155 | iter->cur.wc_valid = false; | ||
156 | /* Whether to set iter->in_shift = false and reset iter->state | ||
157 | or not is not important; the string end is reached anyway. */ | ||
158 | } | ||
159 | else | ||
160 | { | ||
161 | if (iter->cur.bytes == 0) | ||
162 | { | ||
163 | /* A null wide character was encountered. */ | ||
164 | iter->cur.bytes = 1; | ||
165 | assert (*iter->cur.ptr == '\0'); | ||
166 | assert (iter->cur.wc == 0); | ||
167 | } | ||
168 | iter->cur.wc_valid = true; | ||
169 | |||
170 | /* When in the initial state, we can go back treating ASCII | ||
171 | characters more quickly. */ | ||
172 | if (mbsinit (&iter->state)) | ||
173 | iter->in_shift = false; | ||
174 | } | ||
175 | } | ||
176 | iter->next_done = true; | ||
177 | } | ||
178 | |||
179 | static inline void | ||
180 | mbuiter_multi_reloc (struct mbuiter_multi *iter, ptrdiff_t ptrdiff) | ||
181 | { | ||
182 | iter->cur.ptr += ptrdiff; | ||
183 | } | ||
184 | |||
185 | /* Iteration macros. */ | ||
186 | typedef struct mbuiter_multi mbui_iterator_t; | ||
187 | #define mbui_init(iter, startptr) \ | ||
188 | ((iter).cur.ptr = (startptr), \ | ||
189 | (iter).in_shift = false, memset (&(iter).state, '\0', sizeof (mbstate_t)), \ | ||
190 | (iter).next_done = false) | ||
191 | #define mbui_avail(iter) \ | ||
192 | (mbuiter_multi_next (&(iter)), !mb_isnul ((iter).cur)) | ||
193 | #define mbui_advance(iter) \ | ||
194 | ((iter).cur.ptr += (iter).cur.bytes, (iter).next_done = false) | ||
195 | |||
196 | /* Access to the current character. */ | ||
197 | #define mbui_cur(iter) (iter).cur | ||
198 | #define mbui_cur_ptr(iter) (iter).cur.ptr | ||
199 | |||
200 | /* Relocation. */ | ||
201 | #define mbui_reloc(iter, ptrdiff) mbuiter_multi_reloc (&iter, ptrdiff) | ||
202 | |||
203 | #endif /* _MBUITER_H */ | ||
diff --git a/gl/memchr.c b/gl/memchr.c new file mode 100644 index 00000000..d44ad6de --- /dev/null +++ b/gl/memchr.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* Copyright (C) 1991, 1993, 1996, 1997, 1999, 2000, 2003, 2004, 2006 Free | ||
2 | Software Foundation, Inc. | ||
3 | |||
4 | Based on strlen implementation by Torbjorn Granlund (tege@sics.se), | ||
5 | with help from Dan Sahlin (dan@sics.se) and | ||
6 | commentary by Jim Blandy (jimb@ai.mit.edu); | ||
7 | adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu), | ||
8 | and implemented by Roland McGrath (roland@ai.mit.edu). | ||
9 | |||
10 | NOTE: The canonical source of this file is maintained with the GNU C Library. | ||
11 | Bugs can be reported to bug-glibc@prep.ai.mit.edu. | ||
12 | |||
13 | This program is free software; you can redistribute it and/or modify it | ||
14 | under the terms of the GNU General Public License as published by the | ||
15 | Free Software Foundation; either version 2, or (at your option) any | ||
16 | later version. | ||
17 | |||
18 | This program is distributed in the hope that it will be useful, | ||
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | GNU General Public License for more details. | ||
22 | |||
23 | You should have received a copy of the GNU General Public License | ||
24 | along with this program; if not, write to the Free Software Foundation, | ||
25 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
26 | |||
27 | #ifndef _LIBC | ||
28 | # include <config.h> | ||
29 | #endif | ||
30 | |||
31 | #include <string.h> | ||
32 | |||
33 | #include <stddef.h> | ||
34 | |||
35 | #if defined _LIBC | ||
36 | # include <memcopy.h> | ||
37 | #else | ||
38 | # define reg_char char | ||
39 | #endif | ||
40 | |||
41 | #include <limits.h> | ||
42 | |||
43 | #if HAVE_BP_SYM_H || defined _LIBC | ||
44 | # include <bp-sym.h> | ||
45 | #else | ||
46 | # define BP_SYM(sym) sym | ||
47 | #endif | ||
48 | |||
49 | #undef memchr | ||
50 | #undef __memchr | ||
51 | |||
52 | /* Search no more than N bytes of S for C. */ | ||
53 | void * | ||
54 | __memchr (void const *s, int c_in, size_t n) | ||
55 | { | ||
56 | const unsigned char *char_ptr; | ||
57 | const unsigned long int *longword_ptr; | ||
58 | unsigned long int longword, magic_bits, charmask; | ||
59 | unsigned reg_char c; | ||
60 | int i; | ||
61 | |||
62 | c = (unsigned char) c_in; | ||
63 | |||
64 | /* Handle the first few characters by reading one character at a time. | ||
65 | Do this until CHAR_PTR is aligned on a longword boundary. */ | ||
66 | for (char_ptr = (const unsigned char *) s; | ||
67 | n > 0 && (size_t) char_ptr % sizeof longword != 0; | ||
68 | --n, ++char_ptr) | ||
69 | if (*char_ptr == c) | ||
70 | return (void *) char_ptr; | ||
71 | |||
72 | /* All these elucidatory comments refer to 4-byte longwords, | ||
73 | but the theory applies equally well to any size longwords. */ | ||
74 | |||
75 | longword_ptr = (const unsigned long int *) char_ptr; | ||
76 | |||
77 | /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits | ||
78 | the "holes." Note that there is a hole just to the left of | ||
79 | each byte, with an extra at the end: | ||
80 | |||
81 | bits: 01111110 11111110 11111110 11111111 | ||
82 | bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD | ||
83 | |||
84 | The 1-bits make sure that carries propagate to the next 0-bit. | ||
85 | The 0-bits provide holes for carries to fall into. */ | ||
86 | |||
87 | /* Set MAGIC_BITS to be this pattern of 1 and 0 bits. | ||
88 | Set CHARMASK to be a longword, each of whose bytes is C. */ | ||
89 | |||
90 | magic_bits = 0xfefefefe; | ||
91 | charmask = c | (c << 8); | ||
92 | charmask |= charmask << 16; | ||
93 | #if 0xffffffffU < ULONG_MAX | ||
94 | magic_bits |= magic_bits << 32; | ||
95 | charmask |= charmask << 32; | ||
96 | if (8 < sizeof longword) | ||
97 | for (i = 64; i < sizeof longword * 8; i *= 2) | ||
98 | { | ||
99 | magic_bits |= magic_bits << i; | ||
100 | charmask |= charmask << i; | ||
101 | } | ||
102 | #endif | ||
103 | magic_bits = (ULONG_MAX >> 1) & (magic_bits | 1); | ||
104 | |||
105 | /* Instead of the traditional loop which tests each character, | ||
106 | we will test a longword at a time. The tricky part is testing | ||
107 | if *any of the four* bytes in the longword in question are zero. */ | ||
108 | while (n >= sizeof longword) | ||
109 | { | ||
110 | /* We tentatively exit the loop if adding MAGIC_BITS to | ||
111 | LONGWORD fails to change any of the hole bits of LONGWORD. | ||
112 | |||
113 | 1) Is this safe? Will it catch all the zero bytes? | ||
114 | Suppose there is a byte with all zeros. Any carry bits | ||
115 | propagating from its left will fall into the hole at its | ||
116 | least significant bit and stop. Since there will be no | ||
117 | carry from its most significant bit, the LSB of the | ||
118 | byte to the left will be unchanged, and the zero will be | ||
119 | detected. | ||
120 | |||
121 | 2) Is this worthwhile? Will it ignore everything except | ||
122 | zero bytes? Suppose every byte of LONGWORD has a bit set | ||
123 | somewhere. There will be a carry into bit 8. If bit 8 | ||
124 | is set, this will carry into bit 16. If bit 8 is clear, | ||
125 | one of bits 9-15 must be set, so there will be a carry | ||
126 | into bit 16. Similarly, there will be a carry into bit | ||
127 | 24. If one of bits 24-30 is set, there will be a carry | ||
128 | into bit 31, so all of the hole bits will be changed. | ||
129 | |||
130 | The one misfire occurs when bits 24-30 are clear and bit | ||
131 | 31 is set; in this case, the hole at bit 31 is not | ||
132 | changed. If we had access to the processor carry flag, | ||
133 | we could close this loophole by putting the fourth hole | ||
134 | at bit 32! | ||
135 | |||
136 | So it ignores everything except 128's, when they're aligned | ||
137 | properly. | ||
138 | |||
139 | 3) But wait! Aren't we looking for C, not zero? | ||
140 | Good point. So what we do is XOR LONGWORD with a longword, | ||
141 | each of whose bytes is C. This turns each byte that is C | ||
142 | into a zero. */ | ||
143 | |||
144 | longword = *longword_ptr++ ^ charmask; | ||
145 | |||
146 | /* Add MAGIC_BITS to LONGWORD. */ | ||
147 | if ((((longword + magic_bits) | ||
148 | |||
149 | /* Set those bits that were unchanged by the addition. */ | ||
150 | ^ ~longword) | ||
151 | |||
152 | /* Look at only the hole bits. If any of the hole bits | ||
153 | are unchanged, most likely one of the bytes was a | ||
154 | zero. */ | ||
155 | & ~magic_bits) != 0) | ||
156 | { | ||
157 | /* Which of the bytes was C? If none of them were, it was | ||
158 | a misfire; continue the search. */ | ||
159 | |||
160 | const unsigned char *cp = (const unsigned char *) (longword_ptr - 1); | ||
161 | |||
162 | if (cp[0] == c) | ||
163 | return (void *) cp; | ||
164 | if (cp[1] == c) | ||
165 | return (void *) &cp[1]; | ||
166 | if (cp[2] == c) | ||
167 | return (void *) &cp[2]; | ||
168 | if (cp[3] == c) | ||
169 | return (void *) &cp[3]; | ||
170 | if (4 < sizeof longword && cp[4] == c) | ||
171 | return (void *) &cp[4]; | ||
172 | if (5 < sizeof longword && cp[5] == c) | ||
173 | return (void *) &cp[5]; | ||
174 | if (6 < sizeof longword && cp[6] == c) | ||
175 | return (void *) &cp[6]; | ||
176 | if (7 < sizeof longword && cp[7] == c) | ||
177 | return (void *) &cp[7]; | ||
178 | if (8 < sizeof longword) | ||
179 | for (i = 8; i < sizeof longword; i++) | ||
180 | if (cp[i] == c) | ||
181 | return (void *) &cp[i]; | ||
182 | } | ||
183 | |||
184 | n -= sizeof longword; | ||
185 | } | ||
186 | |||
187 | char_ptr = (const unsigned char *) longword_ptr; | ||
188 | |||
189 | while (n-- > 0) | ||
190 | { | ||
191 | if (*char_ptr == c) | ||
192 | return (void *) char_ptr; | ||
193 | else | ||
194 | ++char_ptr; | ||
195 | } | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | #ifdef weak_alias | ||
200 | weak_alias (__memchr, BP_SYM (memchr)) | ||
201 | #endif | ||
diff --git a/gl/minmax.h b/gl/minmax.h new file mode 100644 index 00000000..975ea76d --- /dev/null +++ b/gl/minmax.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* MIN, MAX macros. | ||
2 | Copyright (C) 1995, 1998, 2001, 2003, 2005 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _MINMAX_H | ||
19 | #define _MINMAX_H | ||
20 | |||
21 | /* Note: MIN, MAX are also defined in <sys/param.h> on some systems | ||
22 | (glibc, IRIX, HP-UX, OSF/1). Therefore you might get warnings about | ||
23 | MIN, MAX macro redefinitions on some systems; the workaround is to | ||
24 | #include this file as the last one among the #include list. */ | ||
25 | |||
26 | /* Before we define the following symbols we get the <limits.h> file | ||
27 | since otherwise we get redefinitions on some systems if <limits.h> is | ||
28 | included after this file. Likewise for <sys/param.h>. | ||
29 | If more than one of these system headers define MIN and MAX, pick just | ||
30 | one of the headers (because the definitions most likely are the same). */ | ||
31 | #if HAVE_MINMAX_IN_LIMITS_H | ||
32 | # include <limits.h> | ||
33 | #elif HAVE_MINMAX_IN_SYS_PARAM_H | ||
34 | # include <sys/param.h> | ||
35 | #endif | ||
36 | |||
37 | /* Note: MIN and MAX should be used with two arguments of the | ||
38 | same type. They might not return the minimum and maximum of their two | ||
39 | arguments, if the arguments have different types or have unusual | ||
40 | floating-point values. For example, on a typical host with 32-bit 'int', | ||
41 | 64-bit 'long long', and 64-bit IEEE 754 'double' types: | ||
42 | |||
43 | MAX (-1, 2147483648) returns 4294967295. | ||
44 | MAX (9007199254740992.0, 9007199254740993) returns 9007199254740992.0. | ||
45 | MAX (NaN, 0.0) returns 0.0. | ||
46 | MAX (+0.0, -0.0) returns -0.0. | ||
47 | |||
48 | and in each case the answer is in some sense bogus. */ | ||
49 | |||
50 | /* MAX(a,b) returns the maximum of A and B. */ | ||
51 | #ifndef MAX | ||
52 | # define MAX(a,b) ((a) > (b) ? (a) : (b)) | ||
53 | #endif | ||
54 | |||
55 | /* MIN(a,b) returns the minimum of A and B. */ | ||
56 | #ifndef MIN | ||
57 | # define MIN(a,b) ((a) < (b) ? (a) : (b)) | ||
58 | #endif | ||
59 | |||
60 | #endif /* _MINMAX_H */ | ||
diff --git a/gl/mountlist.c b/gl/mountlist.c new file mode 100644 index 00000000..bb01f91e --- /dev/null +++ b/gl/mountlist.c | |||
@@ -0,0 +1,889 @@ | |||
1 | /* mountlist.c -- return a list of mounted file systems | ||
2 | |||
3 | Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, | ||
4 | 2004, 2005, 2006 Free Software Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | #include "mountlist.h" | ||
23 | |||
24 | #include <limits.h> | ||
25 | #include <stdio.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | |||
29 | #include "xalloc.h" | ||
30 | |||
31 | #ifndef strstr | ||
32 | char *strstr (); | ||
33 | #endif | ||
34 | |||
35 | #include <errno.h> | ||
36 | |||
37 | #include <fcntl.h> | ||
38 | |||
39 | #include <unistd.h> | ||
40 | |||
41 | #if HAVE_SYS_PARAM_H | ||
42 | # include <sys/param.h> | ||
43 | #endif | ||
44 | |||
45 | #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */ | ||
46 | # if HAVE_SYS_UCRED_H | ||
47 | # include <grp.h> /* needed on OSF V4.0 for definition of NGROUPS, | ||
48 | NGROUPS is used as an array dimension in ucred.h */ | ||
49 | # include <sys/ucred.h> /* needed by powerpc-apple-darwin1.3.7 */ | ||
50 | # endif | ||
51 | # if HAVE_SYS_MOUNT_H | ||
52 | # include <sys/mount.h> | ||
53 | # endif | ||
54 | # if HAVE_SYS_FS_TYPES_H | ||
55 | # include <sys/fs_types.h> /* needed by powerpc-apple-darwin1.3.7 */ | ||
56 | # endif | ||
57 | # if HAVE_STRUCT_FSSTAT_F_FSTYPENAME | ||
58 | # define FS_TYPE(Ent) ((Ent).f_fstypename) | ||
59 | # else | ||
60 | # define FS_TYPE(Ent) mnt_names[(Ent).f_type] | ||
61 | # endif | ||
62 | #endif /* MOUNTED_GETFSSTAT */ | ||
63 | |||
64 | #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ | ||
65 | # include <mntent.h> | ||
66 | # if !defined MOUNTED | ||
67 | # if defined _PATH_MOUNTED /* GNU libc */ | ||
68 | # define MOUNTED _PATH_MOUNTED | ||
69 | # endif | ||
70 | # if defined MNT_MNTTAB /* HP-UX. */ | ||
71 | # define MOUNTED MNT_MNTTAB | ||
72 | # endif | ||
73 | # if defined MNTTABNAME /* Dynix. */ | ||
74 | # define MOUNTED MNTTABNAME | ||
75 | # endif | ||
76 | # endif | ||
77 | #endif | ||
78 | |||
79 | #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ | ||
80 | # include <sys/mount.h> | ||
81 | #endif | ||
82 | |||
83 | #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ | ||
84 | # include <sys/statvfs.h> | ||
85 | #endif | ||
86 | |||
87 | #ifdef MOUNTED_GETMNT /* Ultrix. */ | ||
88 | # include <sys/mount.h> | ||
89 | # include <sys/fs_types.h> | ||
90 | #endif | ||
91 | |||
92 | #ifdef MOUNTED_FS_STAT_DEV /* BeOS. */ | ||
93 | # include <fs_info.h> | ||
94 | # include <dirent.h> | ||
95 | #endif | ||
96 | |||
97 | #ifdef MOUNTED_FREAD /* SVR2. */ | ||
98 | # include <mnttab.h> | ||
99 | #endif | ||
100 | |||
101 | #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */ | ||
102 | # include <mnttab.h> | ||
103 | # include <sys/fstyp.h> | ||
104 | # include <sys/statfs.h> | ||
105 | #endif | ||
106 | |||
107 | #ifdef MOUNTED_LISTMNTENT | ||
108 | # include <mntent.h> | ||
109 | #endif | ||
110 | |||
111 | #ifdef MOUNTED_GETMNTENT2 /* SVR4. */ | ||
112 | # include <sys/mnttab.h> | ||
113 | #endif | ||
114 | |||
115 | #ifdef MOUNTED_VMOUNT /* AIX. */ | ||
116 | # include <fshelp.h> | ||
117 | # include <sys/vfs.h> | ||
118 | #endif | ||
119 | |||
120 | #ifdef DOLPHIN | ||
121 | /* So special that it's not worth putting this in autoconf. */ | ||
122 | # undef MOUNTED_FREAD_FSTYP | ||
123 | # define MOUNTED_GETMNTTBL | ||
124 | #endif | ||
125 | |||
126 | #if HAVE_SYS_MNTENT_H | ||
127 | /* This is to get MNTOPT_IGNORE on e.g. SVR4. */ | ||
128 | # include <sys/mntent.h> | ||
129 | #endif | ||
130 | |||
131 | #undef MNT_IGNORE | ||
132 | #if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT | ||
133 | # define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE) | ||
134 | #else | ||
135 | # define MNT_IGNORE(M) 0 | ||
136 | #endif | ||
137 | |||
138 | #if USE_UNLOCKED_IO | ||
139 | # include "unlocked-io.h" | ||
140 | #endif | ||
141 | |||
142 | #ifndef SIZE_MAX | ||
143 | # define SIZE_MAX ((size_t) -1) | ||
144 | #endif | ||
145 | |||
146 | /* The results of open() in this file are not used with fchdir, | ||
147 | therefore save some unnecessary work in fchdir.c. */ | ||
148 | #undef open | ||
149 | #undef close | ||
150 | |||
151 | /* The results of opendir() in this file are not used with dirfd and fchdir, | ||
152 | therefore save some unnecessary work in fchdir.c. */ | ||
153 | #undef opendir | ||
154 | #undef closedir | ||
155 | |||
156 | #ifndef ME_DUMMY | ||
157 | # define ME_DUMMY(Fs_name, Fs_type) \ | ||
158 | (strcmp (Fs_type, "autofs") == 0 \ | ||
159 | || strcmp (Fs_type, "none") == 0 \ | ||
160 | || strcmp (Fs_type, "proc") == 0 \ | ||
161 | || strcmp (Fs_type, "subfs") == 0 \ | ||
162 | /* for NetBSD 3.0 */ \ | ||
163 | || strcmp (Fs_type, "kernfs") == 0 \ | ||
164 | /* for Irix 6.5 */ \ | ||
165 | || strcmp (Fs_type, "ignore") == 0) | ||
166 | #endif | ||
167 | |||
168 | #ifndef ME_REMOTE | ||
169 | /* A file system is `remote' if its Fs_name contains a `:' | ||
170 | or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */ | ||
171 | # define ME_REMOTE(Fs_name, Fs_type) \ | ||
172 | (strchr (Fs_name, ':') != NULL \ | ||
173 | || ((Fs_name)[0] == '/' \ | ||
174 | && (Fs_name)[1] == '/' \ | ||
175 | && (strcmp (Fs_type, "smbfs") == 0 \ | ||
176 | || strcmp (Fs_type, "cifs") == 0))) | ||
177 | #endif | ||
178 | |||
179 | #if MOUNTED_GETMNTINFO | ||
180 | |||
181 | # if ! HAVE_STRUCT_STATFS_F_FSTYPENAME | ||
182 | static char * | ||
183 | fstype_to_string (short int t) | ||
184 | { | ||
185 | switch (t) | ||
186 | { | ||
187 | # ifdef MOUNT_PC | ||
188 | case MOUNT_PC: | ||
189 | return "pc"; | ||
190 | # endif | ||
191 | # ifdef MOUNT_MFS | ||
192 | case MOUNT_MFS: | ||
193 | return "mfs"; | ||
194 | # endif | ||
195 | # ifdef MOUNT_LO | ||
196 | case MOUNT_LO: | ||
197 | return "lo"; | ||
198 | # endif | ||
199 | # ifdef MOUNT_TFS | ||
200 | case MOUNT_TFS: | ||
201 | return "tfs"; | ||
202 | # endif | ||
203 | # ifdef MOUNT_TMP | ||
204 | case MOUNT_TMP: | ||
205 | return "tmp"; | ||
206 | # endif | ||
207 | # ifdef MOUNT_UFS | ||
208 | case MOUNT_UFS: | ||
209 | return "ufs" ; | ||
210 | # endif | ||
211 | # ifdef MOUNT_NFS | ||
212 | case MOUNT_NFS: | ||
213 | return "nfs" ; | ||
214 | # endif | ||
215 | # ifdef MOUNT_MSDOS | ||
216 | case MOUNT_MSDOS: | ||
217 | return "msdos" ; | ||
218 | # endif | ||
219 | # ifdef MOUNT_LFS | ||
220 | case MOUNT_LFS: | ||
221 | return "lfs" ; | ||
222 | # endif | ||
223 | # ifdef MOUNT_LOFS | ||
224 | case MOUNT_LOFS: | ||
225 | return "lofs" ; | ||
226 | # endif | ||
227 | # ifdef MOUNT_FDESC | ||
228 | case MOUNT_FDESC: | ||
229 | return "fdesc" ; | ||
230 | # endif | ||
231 | # ifdef MOUNT_PORTAL | ||
232 | case MOUNT_PORTAL: | ||
233 | return "portal" ; | ||
234 | # endif | ||
235 | # ifdef MOUNT_NULL | ||
236 | case MOUNT_NULL: | ||
237 | return "null" ; | ||
238 | # endif | ||
239 | # ifdef MOUNT_UMAP | ||
240 | case MOUNT_UMAP: | ||
241 | return "umap" ; | ||
242 | # endif | ||
243 | # ifdef MOUNT_KERNFS | ||
244 | case MOUNT_KERNFS: | ||
245 | return "kernfs" ; | ||
246 | # endif | ||
247 | # ifdef MOUNT_PROCFS | ||
248 | case MOUNT_PROCFS: | ||
249 | return "procfs" ; | ||
250 | # endif | ||
251 | # ifdef MOUNT_AFS | ||
252 | case MOUNT_AFS: | ||
253 | return "afs" ; | ||
254 | # endif | ||
255 | # ifdef MOUNT_CD9660 | ||
256 | case MOUNT_CD9660: | ||
257 | return "cd9660" ; | ||
258 | # endif | ||
259 | # ifdef MOUNT_UNION | ||
260 | case MOUNT_UNION: | ||
261 | return "union" ; | ||
262 | # endif | ||
263 | # ifdef MOUNT_DEVFS | ||
264 | case MOUNT_DEVFS: | ||
265 | return "devfs" ; | ||
266 | # endif | ||
267 | # ifdef MOUNT_EXT2FS | ||
268 | case MOUNT_EXT2FS: | ||
269 | return "ext2fs" ; | ||
270 | # endif | ||
271 | default: | ||
272 | return "?"; | ||
273 | } | ||
274 | } | ||
275 | # endif | ||
276 | |||
277 | static char * | ||
278 | fsp_to_string (const struct statfs *fsp) | ||
279 | { | ||
280 | # if HAVE_STRUCT_STATFS_F_FSTYPENAME | ||
281 | return (char *) (fsp->f_fstypename); | ||
282 | # else | ||
283 | return fstype_to_string (fsp->f_type); | ||
284 | # endif | ||
285 | } | ||
286 | |||
287 | #endif /* MOUNTED_GETMNTINFO */ | ||
288 | |||
289 | #ifdef MOUNTED_VMOUNT /* AIX. */ | ||
290 | static char * | ||
291 | fstype_to_string (int t) | ||
292 | { | ||
293 | struct vfs_ent *e; | ||
294 | |||
295 | e = getvfsbytype (t); | ||
296 | if (!e || !e->vfsent_name) | ||
297 | return "none"; | ||
298 | else | ||
299 | return e->vfsent_name; | ||
300 | } | ||
301 | #endif /* MOUNTED_VMOUNT */ | ||
302 | |||
303 | |||
304 | #if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2 | ||
305 | |||
306 | /* Return the device number from MOUNT_OPTIONS, if possible. | ||
307 | Otherwise return (dev_t) -1. */ | ||
308 | |||
309 | static dev_t | ||
310 | dev_from_mount_options (char const *mount_options) | ||
311 | { | ||
312 | /* GNU/Linux allows file system implementations to define their own | ||
313 | meaning for "dev=" mount options, so don't trust the meaning | ||
314 | here. */ | ||
315 | # ifndef __linux__ | ||
316 | |||
317 | static char const dev_pattern[] = ",dev="; | ||
318 | char const *devopt = strstr (mount_options, dev_pattern); | ||
319 | |||
320 | if (devopt) | ||
321 | { | ||
322 | char const *optval = devopt + sizeof dev_pattern - 1; | ||
323 | char *optvalend; | ||
324 | unsigned long int dev; | ||
325 | errno = 0; | ||
326 | dev = strtoul (optval, &optvalend, 16); | ||
327 | if (optval != optvalend | ||
328 | && (*optvalend == '\0' || *optvalend == ',') | ||
329 | && ! (dev == ULONG_MAX && errno == ERANGE) | ||
330 | && dev == (dev_t) dev) | ||
331 | return dev; | ||
332 | } | ||
333 | |||
334 | # endif | ||
335 | |||
336 | return -1; | ||
337 | } | ||
338 | |||
339 | #endif | ||
340 | |||
341 | /* Return a list of the currently mounted file systems, or NULL on error. | ||
342 | Add each entry to the tail of the list so that they stay in order. | ||
343 | If NEED_FS_TYPE is true, ensure that the file system type fields in | ||
344 | the returned list are valid. Otherwise, they might not be. */ | ||
345 | |||
346 | struct mount_entry * | ||
347 | read_file_system_list (bool need_fs_type) | ||
348 | { | ||
349 | struct mount_entry *mount_list; | ||
350 | struct mount_entry *me; | ||
351 | struct mount_entry **mtail = &mount_list; | ||
352 | |||
353 | #ifdef MOUNTED_LISTMNTENT | ||
354 | { | ||
355 | struct tabmntent *mntlist, *p; | ||
356 | struct mntent *mnt; | ||
357 | struct mount_entry *me; | ||
358 | |||
359 | /* the third and fourth arguments could be used to filter mounts, | ||
360 | but Crays doesn't seem to have any mounts that we want to | ||
361 | remove. Specifically, automount create normal NFS mounts. | ||
362 | */ | ||
363 | |||
364 | if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0) | ||
365 | return NULL; | ||
366 | for (p = mntlist; p; p = p->next) { | ||
367 | mnt = p->ment; | ||
368 | me = xmalloc (sizeof *me); | ||
369 | me->me_devname = xstrdup (mnt->mnt_fsname); | ||
370 | me->me_mountdir = xstrdup (mnt->mnt_dir); | ||
371 | me->me_type = xstrdup (mnt->mnt_type); | ||
372 | me->me_type_malloced = 1; | ||
373 | me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); | ||
374 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); | ||
375 | me->me_dev = -1; | ||
376 | *mtail = me; | ||
377 | mtail = &me->me_next; | ||
378 | } | ||
379 | freemntlist (mntlist); | ||
380 | } | ||
381 | #endif | ||
382 | |||
383 | #ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ | ||
384 | { | ||
385 | struct mntent *mnt; | ||
386 | char *table = MOUNTED; | ||
387 | FILE *fp; | ||
388 | |||
389 | fp = setmntent (table, "r"); | ||
390 | if (fp == NULL) | ||
391 | return NULL; | ||
392 | |||
393 | while ((mnt = getmntent (fp))) | ||
394 | { | ||
395 | me = xmalloc (sizeof *me); | ||
396 | me->me_devname = xstrdup (mnt->mnt_fsname); | ||
397 | me->me_mountdir = xstrdup (mnt->mnt_dir); | ||
398 | me->me_type = xstrdup (mnt->mnt_type); | ||
399 | me->me_type_malloced = 1; | ||
400 | me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); | ||
401 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); | ||
402 | me->me_dev = dev_from_mount_options (mnt->mnt_opts); | ||
403 | |||
404 | /* Add to the linked list. */ | ||
405 | *mtail = me; | ||
406 | mtail = &me->me_next; | ||
407 | } | ||
408 | |||
409 | if (endmntent (fp) == 0) | ||
410 | goto free_then_fail; | ||
411 | } | ||
412 | #endif /* MOUNTED_GETMNTENT1. */ | ||
413 | |||
414 | #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ | ||
415 | { | ||
416 | struct statfs *fsp; | ||
417 | int entries; | ||
418 | |||
419 | entries = getmntinfo (&fsp, MNT_NOWAIT); | ||
420 | if (entries < 0) | ||
421 | return NULL; | ||
422 | for (; entries-- > 0; fsp++) | ||
423 | { | ||
424 | char *fs_type = fsp_to_string (fsp); | ||
425 | |||
426 | me = xmalloc (sizeof *me); | ||
427 | me->me_devname = xstrdup (fsp->f_mntfromname); | ||
428 | me->me_mountdir = xstrdup (fsp->f_mntonname); | ||
429 | me->me_type = fs_type; | ||
430 | me->me_type_malloced = 0; | ||
431 | me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); | ||
432 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); | ||
433 | me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ | ||
434 | |||
435 | /* Add to the linked list. */ | ||
436 | *mtail = me; | ||
437 | mtail = &me->me_next; | ||
438 | } | ||
439 | } | ||
440 | #endif /* MOUNTED_GETMNTINFO */ | ||
441 | |||
442 | #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ | ||
443 | { | ||
444 | struct statvfs *fsp; | ||
445 | int entries; | ||
446 | |||
447 | entries = getmntinfo (&fsp, MNT_NOWAIT); | ||
448 | if (entries < 0) | ||
449 | return NULL; | ||
450 | for (; entries-- > 0; fsp++) | ||
451 | { | ||
452 | me = xmalloc (sizeof *me); | ||
453 | me->me_devname = xstrdup (fsp->f_mntfromname); | ||
454 | me->me_mountdir = xstrdup (fsp->f_mntonname); | ||
455 | me->me_type = xstrdup (fsp->f_fstypename); | ||
456 | me->me_type_malloced = 1; | ||
457 | me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); | ||
458 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); | ||
459 | me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ | ||
460 | |||
461 | /* Add to the linked list. */ | ||
462 | *mtail = me; | ||
463 | mtail = &me->me_next; | ||
464 | } | ||
465 | } | ||
466 | #endif /* MOUNTED_GETMNTINFO2 */ | ||
467 | |||
468 | #ifdef MOUNTED_GETMNT /* Ultrix. */ | ||
469 | { | ||
470 | int offset = 0; | ||
471 | int val; | ||
472 | struct fs_data fsd; | ||
473 | |||
474 | while (errno = 0, | ||
475 | 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, | ||
476 | (char *) 0))) | ||
477 | { | ||
478 | me = xmalloc (sizeof *me); | ||
479 | me->me_devname = xstrdup (fsd.fd_req.devname); | ||
480 | me->me_mountdir = xstrdup (fsd.fd_req.path); | ||
481 | me->me_type = gt_names[fsd.fd_req.fstype]; | ||
482 | me->me_type_malloced = 0; | ||
483 | me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); | ||
484 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); | ||
485 | me->me_dev = fsd.fd_req.dev; | ||
486 | |||
487 | /* Add to the linked list. */ | ||
488 | *mtail = me; | ||
489 | mtail = &me->me_next; | ||
490 | } | ||
491 | if (val < 0) | ||
492 | goto free_then_fail; | ||
493 | } | ||
494 | #endif /* MOUNTED_GETMNT. */ | ||
495 | |||
496 | #if defined MOUNTED_FS_STAT_DEV /* BeOS */ | ||
497 | { | ||
498 | /* The next_dev() and fs_stat_dev() system calls give the list of | ||
499 | all file systems, including the information returned by statvfs() | ||
500 | (fs type, total blocks, free blocks etc.), but without the mount | ||
501 | point. But on BeOS all file systems except / are mounted in the | ||
502 | rootfs, directly under /. | ||
503 | The directory name of the mount point is often, but not always, | ||
504 | identical to the volume name of the device. | ||
505 | We therefore get the list of subdirectories of /, and the list | ||
506 | of all file systems, and match the two lists. */ | ||
507 | |||
508 | DIR *dirp; | ||
509 | struct rootdir_entry | ||
510 | { | ||
511 | char *name; | ||
512 | dev_t dev; | ||
513 | ino_t ino; | ||
514 | struct rootdir_entry *next; | ||
515 | }; | ||
516 | struct rootdir_entry *rootdir_list; | ||
517 | struct rootdir_entry **rootdir_tail; | ||
518 | int32 pos; | ||
519 | dev_t dev; | ||
520 | fs_info fi; | ||
521 | |||
522 | /* All volumes are mounted in the rootfs, directly under /. */ | ||
523 | rootdir_list = NULL; | ||
524 | rootdir_tail = &rootdir_list; | ||
525 | dirp = opendir ("/"); | ||
526 | if (dirp) | ||
527 | { | ||
528 | struct dirent *d; | ||
529 | |||
530 | while ((d = readdir (dirp)) != NULL) | ||
531 | { | ||
532 | char *name; | ||
533 | struct stat statbuf; | ||
534 | |||
535 | if (strcmp (d->d_name, "..") == 0) | ||
536 | continue; | ||
537 | |||
538 | if (strcmp (d->d_name, ".") == 0) | ||
539 | name = xstrdup ("/"); | ||
540 | else | ||
541 | { | ||
542 | name = xmalloc (1 + strlen (d->d_name) + 1); | ||
543 | name[0] = '/'; | ||
544 | strcpy (name + 1, d->d_name); | ||
545 | } | ||
546 | |||
547 | if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode)) | ||
548 | { | ||
549 | struct rootdir_entry *re = xmalloc (sizeof *re); | ||
550 | re->name = name; | ||
551 | re->dev = statbuf.st_dev; | ||
552 | re->ino = statbuf.st_ino; | ||
553 | |||
554 | /* Add to the linked list. */ | ||
555 | *rootdir_tail = re; | ||
556 | rootdir_tail = &re->next; | ||
557 | } | ||
558 | else | ||
559 | free (name); | ||
560 | } | ||
561 | closedir (dirp); | ||
562 | } | ||
563 | *rootdir_tail = NULL; | ||
564 | |||
565 | for (pos = 0; (dev = next_dev (&pos)) >= 0; ) | ||
566 | if (fs_stat_dev (dev, &fi) >= 0) | ||
567 | { | ||
568 | /* Note: fi.dev == dev. */ | ||
569 | struct rootdir_entry *re; | ||
570 | |||
571 | for (re = rootdir_list; re; re = re->next) | ||
572 | if (re->dev == fi.dev && re->ino == fi.root) | ||
573 | break; | ||
574 | |||
575 | me = xmalloc (sizeof *me); | ||
576 | me->me_devname = xstrdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name); | ||
577 | me->me_mountdir = xstrdup (re != NULL ? re->name : fi.fsh_name); | ||
578 | me->me_type = xstrdup (fi.fsh_name); | ||
579 | me->me_type_malloced = 1; | ||
580 | me->me_dev = fi.dev; | ||
581 | me->me_dummy = 0; | ||
582 | me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0; | ||
583 | |||
584 | /* Add to the linked list. */ | ||
585 | *mtail = me; | ||
586 | mtail = &me->me_next; | ||
587 | } | ||
588 | *mtail = NULL; | ||
589 | |||
590 | while (rootdir_list != NULL) | ||
591 | { | ||
592 | struct rootdir_entry *re = rootdir_list; | ||
593 | rootdir_list = re->next; | ||
594 | free (re->name); | ||
595 | free (re); | ||
596 | } | ||
597 | } | ||
598 | #endif /* MOUNTED_FS_STAT_DEV */ | ||
599 | |||
600 | #if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */ | ||
601 | { | ||
602 | int numsys, counter; | ||
603 | size_t bufsize; | ||
604 | struct statfs *stats; | ||
605 | |||
606 | numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT); | ||
607 | if (numsys < 0) | ||
608 | return (NULL); | ||
609 | if (SIZE_MAX / sizeof *stats <= numsys) | ||
610 | xalloc_die (); | ||
611 | |||
612 | bufsize = (1 + numsys) * sizeof *stats; | ||
613 | stats = xmalloc (bufsize); | ||
614 | numsys = getfsstat (stats, bufsize, MNT_NOWAIT); | ||
615 | |||
616 | if (numsys < 0) | ||
617 | { | ||
618 | free (stats); | ||
619 | return (NULL); | ||
620 | } | ||
621 | |||
622 | for (counter = 0; counter < numsys; counter++) | ||
623 | { | ||
624 | me = xmalloc (sizeof *me); | ||
625 | me->me_devname = xstrdup (stats[counter].f_mntfromname); | ||
626 | me->me_mountdir = xstrdup (stats[counter].f_mntonname); | ||
627 | me->me_type = xstrdup (FS_TYPE (stats[counter])); | ||
628 | me->me_type_malloced = 1; | ||
629 | me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); | ||
630 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); | ||
631 | me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ | ||
632 | |||
633 | /* Add to the linked list. */ | ||
634 | *mtail = me; | ||
635 | mtail = &me->me_next; | ||
636 | } | ||
637 | |||
638 | free (stats); | ||
639 | } | ||
640 | #endif /* MOUNTED_GETFSSTAT */ | ||
641 | |||
642 | #if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */ | ||
643 | { | ||
644 | struct mnttab mnt; | ||
645 | char *table = "/etc/mnttab"; | ||
646 | FILE *fp; | ||
647 | |||
648 | fp = fopen (table, "r"); | ||
649 | if (fp == NULL) | ||
650 | return NULL; | ||
651 | |||
652 | while (fread (&mnt, sizeof mnt, 1, fp) > 0) | ||
653 | { | ||
654 | me = xmalloc (sizeof *me); | ||
655 | # ifdef GETFSTYP /* SVR3. */ | ||
656 | me->me_devname = xstrdup (mnt.mt_dev); | ||
657 | # else | ||
658 | me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6); | ||
659 | strcpy (me->me_devname, "/dev/"); | ||
660 | strcpy (me->me_devname + 5, mnt.mt_dev); | ||
661 | # endif | ||
662 | me->me_mountdir = xstrdup (mnt.mt_filsys); | ||
663 | me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ | ||
664 | me->me_type = ""; | ||
665 | me->me_type_malloced = 0; | ||
666 | # ifdef GETFSTYP /* SVR3. */ | ||
667 | if (need_fs_type) | ||
668 | { | ||
669 | struct statfs fsd; | ||
670 | char typebuf[FSTYPSZ]; | ||
671 | |||
672 | if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1 | ||
673 | && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1) | ||
674 | { | ||
675 | me->me_type = xstrdup (typebuf); | ||
676 | me->me_type_malloced = 1; | ||
677 | } | ||
678 | } | ||
679 | # endif | ||
680 | me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); | ||
681 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); | ||
682 | |||
683 | /* Add to the linked list. */ | ||
684 | *mtail = me; | ||
685 | mtail = &me->me_next; | ||
686 | } | ||
687 | |||
688 | if (ferror (fp)) | ||
689 | { | ||
690 | /* The last fread() call must have failed. */ | ||
691 | int saved_errno = errno; | ||
692 | fclose (fp); | ||
693 | errno = saved_errno; | ||
694 | goto free_then_fail; | ||
695 | } | ||
696 | |||
697 | if (fclose (fp) == EOF) | ||
698 | goto free_then_fail; | ||
699 | } | ||
700 | #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */ | ||
701 | |||
702 | #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */ | ||
703 | { | ||
704 | struct mntent **mnttbl = getmnttbl (), **ent; | ||
705 | for (ent=mnttbl;*ent;ent++) | ||
706 | { | ||
707 | me = xmalloc (sizeof *me); | ||
708 | me->me_devname = xstrdup ( (*ent)->mt_resource); | ||
709 | me->me_mountdir = xstrdup ( (*ent)->mt_directory); | ||
710 | me->me_type = xstrdup ((*ent)->mt_fstype); | ||
711 | me->me_type_malloced = 1; | ||
712 | me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); | ||
713 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); | ||
714 | me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ | ||
715 | |||
716 | /* Add to the linked list. */ | ||
717 | *mtail = me; | ||
718 | mtail = &me->me_next; | ||
719 | } | ||
720 | endmnttbl (); | ||
721 | } | ||
722 | #endif | ||
723 | |||
724 | #ifdef MOUNTED_GETMNTENT2 /* SVR4. */ | ||
725 | { | ||
726 | struct mnttab mnt; | ||
727 | char *table = MNTTAB; | ||
728 | FILE *fp; | ||
729 | int ret; | ||
730 | int lockfd = -1; | ||
731 | |||
732 | # if defined F_RDLCK && defined F_SETLKW | ||
733 | /* MNTTAB_LOCK is a macro name of our own invention; it's not present in | ||
734 | e.g. Solaris 2.6. If the SVR4 folks ever define a macro | ||
735 | for this file name, we should use their macro name instead. | ||
736 | (Why not just lock MNTTAB directly? We don't know.) */ | ||
737 | # ifndef MNTTAB_LOCK | ||
738 | # define MNTTAB_LOCK "/etc/.mnttab.lock" | ||
739 | # endif | ||
740 | lockfd = open (MNTTAB_LOCK, O_RDONLY); | ||
741 | if (0 <= lockfd) | ||
742 | { | ||
743 | struct flock flock; | ||
744 | flock.l_type = F_RDLCK; | ||
745 | flock.l_whence = SEEK_SET; | ||
746 | flock.l_start = 0; | ||
747 | flock.l_len = 0; | ||
748 | while (fcntl (lockfd, F_SETLKW, &flock) == -1) | ||
749 | if (errno != EINTR) | ||
750 | { | ||
751 | int saved_errno = errno; | ||
752 | close (lockfd); | ||
753 | errno = saved_errno; | ||
754 | return NULL; | ||
755 | } | ||
756 | } | ||
757 | else if (errno != ENOENT) | ||
758 | return NULL; | ||
759 | # endif | ||
760 | |||
761 | errno = 0; | ||
762 | fp = fopen (table, "r"); | ||
763 | if (fp == NULL) | ||
764 | ret = errno; | ||
765 | else | ||
766 | { | ||
767 | while ((ret = getmntent (fp, &mnt)) == 0) | ||
768 | { | ||
769 | me = xmalloc (sizeof *me); | ||
770 | me->me_devname = xstrdup (mnt.mnt_special); | ||
771 | me->me_mountdir = xstrdup (mnt.mnt_mountp); | ||
772 | me->me_type = xstrdup (mnt.mnt_fstype); | ||
773 | me->me_type_malloced = 1; | ||
774 | me->me_dummy = MNT_IGNORE (&mnt) != 0; | ||
775 | me->me_remote = ME_REMOTE (me->me_devname, me->me_type); | ||
776 | me->me_dev = dev_from_mount_options (mnt.mnt_mntopts); | ||
777 | |||
778 | /* Add to the linked list. */ | ||
779 | *mtail = me; | ||
780 | mtail = &me->me_next; | ||
781 | } | ||
782 | |||
783 | ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1; | ||
784 | } | ||
785 | |||
786 | if (0 <= lockfd && close (lockfd) != 0) | ||
787 | ret = errno; | ||
788 | |||
789 | if (0 <= ret) | ||
790 | { | ||
791 | errno = ret; | ||
792 | goto free_then_fail; | ||
793 | } | ||
794 | } | ||
795 | #endif /* MOUNTED_GETMNTENT2. */ | ||
796 | |||
797 | #ifdef MOUNTED_VMOUNT /* AIX. */ | ||
798 | { | ||
799 | int bufsize; | ||
800 | char *entries, *thisent; | ||
801 | struct vmount *vmp; | ||
802 | int n_entries; | ||
803 | int i; | ||
804 | |||
805 | /* Ask how many bytes to allocate for the mounted file system info. */ | ||
806 | if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0) | ||
807 | return NULL; | ||
808 | entries = xmalloc (bufsize); | ||
809 | |||
810 | /* Get the list of mounted file systems. */ | ||
811 | n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries); | ||
812 | if (n_entries < 0) | ||
813 | { | ||
814 | int saved_errno = errno; | ||
815 | free (entries); | ||
816 | errno = saved_errno; | ||
817 | return NULL; | ||
818 | } | ||
819 | |||
820 | for (i = 0, thisent = entries; | ||
821 | i < n_entries; | ||
822 | i++, thisent += vmp->vmt_length) | ||
823 | { | ||
824 | char *options, *ignore; | ||
825 | |||
826 | vmp = (struct vmount *) thisent; | ||
827 | me = xmalloc (sizeof *me); | ||
828 | if (vmp->vmt_flags & MNT_REMOTE) | ||
829 | { | ||
830 | char *host, *dir; | ||
831 | |||
832 | me->me_remote = 1; | ||
833 | /* Prepend the remote dirname. */ | ||
834 | host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off; | ||
835 | dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off; | ||
836 | me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2); | ||
837 | strcpy (me->me_devname, host); | ||
838 | strcat (me->me_devname, ":"); | ||
839 | strcat (me->me_devname, dir); | ||
840 | } | ||
841 | else | ||
842 | { | ||
843 | me->me_remote = 0; | ||
844 | me->me_devname = xstrdup (thisent + | ||
845 | vmp->vmt_data[VMT_OBJECT].vmt_off); | ||
846 | } | ||
847 | me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off); | ||
848 | me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype)); | ||
849 | me->me_type_malloced = 1; | ||
850 | options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off; | ||
851 | ignore = strstr (options, "ignore"); | ||
852 | me->me_dummy = (ignore | ||
853 | && (ignore == options || ignore[-1] == ',') | ||
854 | && (ignore[sizeof "ignore" - 1] == ',' | ||
855 | || ignore[sizeof "ignore" - 1] == '\0')); | ||
856 | me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */ | ||
857 | |||
858 | /* Add to the linked list. */ | ||
859 | *mtail = me; | ||
860 | mtail = &me->me_next; | ||
861 | } | ||
862 | free (entries); | ||
863 | } | ||
864 | #endif /* MOUNTED_VMOUNT. */ | ||
865 | |||
866 | *mtail = NULL; | ||
867 | return mount_list; | ||
868 | |||
869 | |||
870 | free_then_fail: | ||
871 | { | ||
872 | int saved_errno = errno; | ||
873 | *mtail = NULL; | ||
874 | |||
875 | while (mount_list) | ||
876 | { | ||
877 | me = mount_list->me_next; | ||
878 | free (mount_list->me_devname); | ||
879 | free (mount_list->me_mountdir); | ||
880 | if (mount_list->me_type_malloced) | ||
881 | free (mount_list->me_type); | ||
882 | free (mount_list); | ||
883 | mount_list = me; | ||
884 | } | ||
885 | |||
886 | errno = saved_errno; | ||
887 | return NULL; | ||
888 | } | ||
889 | } | ||
diff --git a/gl/mountlist.h b/gl/mountlist.h new file mode 100644 index 00000000..7f5a6f77 --- /dev/null +++ b/gl/mountlist.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* mountlist.h -- declarations for list of mounted file systems | ||
2 | |||
3 | Copyright (C) 1991, 1992, 1998, 2000, 2001, 2002, 2003, 2004, 2005 | ||
4 | Free Software Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #ifndef MOUNTLIST_H_ | ||
21 | # define MOUNTLIST_H_ | ||
22 | |||
23 | # include <stdbool.h> | ||
24 | # include <sys/types.h> | ||
25 | |||
26 | /* A mount table entry. */ | ||
27 | struct mount_entry | ||
28 | { | ||
29 | char *me_devname; /* Device node name, including "/dev/". */ | ||
30 | char *me_mountdir; /* Mount point directory name. */ | ||
31 | char *me_type; /* "nfs", "4.2", etc. */ | ||
32 | dev_t me_dev; /* Device number of me_mountdir. */ | ||
33 | unsigned int me_dummy : 1; /* Nonzero for dummy file systems. */ | ||
34 | unsigned int me_remote : 1; /* Nonzero for remote fileystems. */ | ||
35 | unsigned int me_type_malloced : 1; /* Nonzero if me_type was malloced. */ | ||
36 | struct mount_entry *me_next; | ||
37 | }; | ||
38 | |||
39 | struct mount_entry *read_file_system_list (bool need_fs_type); | ||
40 | |||
41 | #endif | ||
diff --git a/gl/open-safer.c b/gl/open-safer.c new file mode 100644 index 00000000..04a72eb7 --- /dev/null +++ b/gl/open-safer.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* Invoke open, but avoid some glitches. | ||
2 | |||
3 | Copyright (C) 2005, 2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Paul Eggert. */ | ||
20 | |||
21 | #include <config.h> | ||
22 | |||
23 | #include "fcntl-safer.h" | ||
24 | |||
25 | #include <fcntl.h> | ||
26 | #include <stdarg.h> | ||
27 | #include "unistd-safer.h" | ||
28 | |||
29 | int | ||
30 | open_safer (char const *file, int flags, ...) | ||
31 | { | ||
32 | mode_t mode = 0; | ||
33 | |||
34 | if (flags & O_CREAT) | ||
35 | { | ||
36 | va_list ap; | ||
37 | va_start (ap, flags); | ||
38 | |||
39 | /* Assume mode_t promotes to int if and only if it is smaller. | ||
40 | This assumption isn't guaranteed by the C standard, but we | ||
41 | don't know of any real-world counterexamples. */ | ||
42 | mode = (sizeof (mode_t) < sizeof (int) | ||
43 | ? va_arg (ap, int) | ||
44 | : va_arg (ap, mode_t)); | ||
45 | |||
46 | va_end (ap); | ||
47 | } | ||
48 | |||
49 | return fd_safer (open (file, flags, mode)); | ||
50 | } | ||
diff --git a/gl/pipe-safer.c b/gl/pipe-safer.c new file mode 100644 index 00000000..e4431b33 --- /dev/null +++ b/gl/pipe-safer.c | |||
@@ -0,0 +1,57 @@ | |||
1 | /* Invoke pipe, but avoid some glitches. | ||
2 | Copyright (C) 2005, 2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | /* Written by Jim Meyering. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | #include "unistd-safer.h" | ||
23 | |||
24 | #include <unistd.h> | ||
25 | #include <errno.h> | ||
26 | |||
27 | /* Like pipe, but ensure that neither of the file descriptors is | ||
28 | STDIN_FILENO, STDOUT_FILENO, or STDERR_FILENO. Fail with ENOSYS on | ||
29 | platforms that lack pipe. */ | ||
30 | |||
31 | int | ||
32 | pipe_safer (int fd[2]) | ||
33 | { | ||
34 | #if HAVE_PIPE | ||
35 | if (pipe (fd) == 0) | ||
36 | { | ||
37 | int i; | ||
38 | for (i = 0; i < 2; i++) | ||
39 | { | ||
40 | fd[i] = fd_safer (fd[i]); | ||
41 | if (fd[i] < 0) | ||
42 | { | ||
43 | int e = errno; | ||
44 | close (fd[1 - i]); | ||
45 | errno = e; | ||
46 | return -1; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | return 0; | ||
51 | } | ||
52 | #else | ||
53 | errno = ENOSYS; | ||
54 | #endif | ||
55 | |||
56 | return -1; | ||
57 | } | ||
diff --git a/gl/printf-args.c b/gl/printf-args.c new file mode 100644 index 00000000..358801c9 --- /dev/null +++ b/gl/printf-args.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* Decomposed printf argument list. | ||
2 | Copyright (C) 1999, 2002-2003, 2005-2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #include <config.h> | ||
19 | |||
20 | /* Specification. */ | ||
21 | #include "printf-args.h" | ||
22 | |||
23 | #ifdef STATIC | ||
24 | STATIC | ||
25 | #endif | ||
26 | int | ||
27 | printf_fetchargs (va_list args, arguments *a) | ||
28 | { | ||
29 | size_t i; | ||
30 | argument *ap; | ||
31 | |||
32 | for (i = 0, ap = &a->arg[0]; i < a->count; i++, ap++) | ||
33 | switch (ap->type) | ||
34 | { | ||
35 | case TYPE_SCHAR: | ||
36 | ap->a.a_schar = va_arg (args, /*signed char*/ int); | ||
37 | break; | ||
38 | case TYPE_UCHAR: | ||
39 | ap->a.a_uchar = va_arg (args, /*unsigned char*/ int); | ||
40 | break; | ||
41 | case TYPE_SHORT: | ||
42 | ap->a.a_short = va_arg (args, /*short*/ int); | ||
43 | break; | ||
44 | case TYPE_USHORT: | ||
45 | ap->a.a_ushort = va_arg (args, /*unsigned short*/ int); | ||
46 | break; | ||
47 | case TYPE_INT: | ||
48 | ap->a.a_int = va_arg (args, int); | ||
49 | break; | ||
50 | case TYPE_UINT: | ||
51 | ap->a.a_uint = va_arg (args, unsigned int); | ||
52 | break; | ||
53 | case TYPE_LONGINT: | ||
54 | ap->a.a_longint = va_arg (args, long int); | ||
55 | break; | ||
56 | case TYPE_ULONGINT: | ||
57 | ap->a.a_ulongint = va_arg (args, unsigned long int); | ||
58 | break; | ||
59 | #ifdef HAVE_LONG_LONG_INT | ||
60 | case TYPE_LONGLONGINT: | ||
61 | ap->a.a_longlongint = va_arg (args, long long int); | ||
62 | break; | ||
63 | case TYPE_ULONGLONGINT: | ||
64 | ap->a.a_ulonglongint = va_arg (args, unsigned long long int); | ||
65 | break; | ||
66 | #endif | ||
67 | case TYPE_DOUBLE: | ||
68 | ap->a.a_double = va_arg (args, double); | ||
69 | break; | ||
70 | #ifdef HAVE_LONG_DOUBLE | ||
71 | case TYPE_LONGDOUBLE: | ||
72 | ap->a.a_longdouble = va_arg (args, long double); | ||
73 | break; | ||
74 | #endif | ||
75 | case TYPE_CHAR: | ||
76 | ap->a.a_char = va_arg (args, int); | ||
77 | break; | ||
78 | #ifdef HAVE_WINT_T | ||
79 | case TYPE_WIDE_CHAR: | ||
80 | /* Although ISO C 99 7.24.1.(2) says that wint_t is "unchanged by | ||
81 | default argument promotions", this is not the case in mingw32, | ||
82 | where wint_t is 'unsigned short'. */ | ||
83 | ap->a.a_wide_char = | ||
84 | (sizeof (wint_t) < sizeof (int) | ||
85 | ? va_arg (args, int) | ||
86 | : va_arg (args, wint_t)); | ||
87 | break; | ||
88 | #endif | ||
89 | case TYPE_STRING: | ||
90 | ap->a.a_string = va_arg (args, const char *); | ||
91 | /* A null pointer is an invalid argument for "%s", but in practice | ||
92 | it occurs quite frequently in printf statements that produce | ||
93 | debug output. Use a fallback in this case. */ | ||
94 | if (ap->a.a_string == NULL) | ||
95 | ap->a.a_string = "(NULL)"; | ||
96 | break; | ||
97 | #ifdef HAVE_WCHAR_T | ||
98 | case TYPE_WIDE_STRING: | ||
99 | ap->a.a_wide_string = va_arg (args, const wchar_t *); | ||
100 | /* A null pointer is an invalid argument for "%ls", but in practice | ||
101 | it occurs quite frequently in printf statements that produce | ||
102 | debug output. Use a fallback in this case. */ | ||
103 | if (ap->a.a_wide_string == NULL) | ||
104 | { | ||
105 | static const wchar_t wide_null_string[] = | ||
106 | { | ||
107 | (wchar_t)'(', | ||
108 | (wchar_t)'N', (wchar_t)'U', (wchar_t)'L', (wchar_t)'L', | ||
109 | (wchar_t)')', | ||
110 | (wchar_t)0 | ||
111 | }; | ||
112 | ap->a.a_wide_string = wide_null_string; | ||
113 | } | ||
114 | break; | ||
115 | #endif | ||
116 | case TYPE_POINTER: | ||
117 | ap->a.a_pointer = va_arg (args, void *); | ||
118 | break; | ||
119 | case TYPE_COUNT_SCHAR_POINTER: | ||
120 | ap->a.a_count_schar_pointer = va_arg (args, signed char *); | ||
121 | break; | ||
122 | case TYPE_COUNT_SHORT_POINTER: | ||
123 | ap->a.a_count_short_pointer = va_arg (args, short *); | ||
124 | break; | ||
125 | case TYPE_COUNT_INT_POINTER: | ||
126 | ap->a.a_count_int_pointer = va_arg (args, int *); | ||
127 | break; | ||
128 | case TYPE_COUNT_LONGINT_POINTER: | ||
129 | ap->a.a_count_longint_pointer = va_arg (args, long int *); | ||
130 | break; | ||
131 | #ifdef HAVE_LONG_LONG_INT | ||
132 | case TYPE_COUNT_LONGLONGINT_POINTER: | ||
133 | ap->a.a_count_longlongint_pointer = va_arg (args, long long int *); | ||
134 | break; | ||
135 | #endif | ||
136 | default: | ||
137 | /* Unknown type. */ | ||
138 | return -1; | ||
139 | } | ||
140 | return 0; | ||
141 | } | ||
diff --git a/gl/printf-args.h b/gl/printf-args.h new file mode 100644 index 00000000..5759da0e --- /dev/null +++ b/gl/printf-args.h | |||
@@ -0,0 +1,136 @@ | |||
1 | /* Decomposed printf argument list. | ||
2 | Copyright (C) 1999, 2002-2003, 2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _PRINTF_ARGS_H | ||
19 | #define _PRINTF_ARGS_H | ||
20 | |||
21 | /* Get size_t. */ | ||
22 | #include <stddef.h> | ||
23 | |||
24 | /* Get wchar_t. */ | ||
25 | #ifdef HAVE_WCHAR_T | ||
26 | # include <stddef.h> | ||
27 | #endif | ||
28 | |||
29 | /* Get wint_t. */ | ||
30 | #ifdef HAVE_WINT_T | ||
31 | # include <wchar.h> | ||
32 | #endif | ||
33 | |||
34 | /* Get va_list. */ | ||
35 | #include <stdarg.h> | ||
36 | |||
37 | |||
38 | /* Argument types */ | ||
39 | typedef enum | ||
40 | { | ||
41 | TYPE_NONE, | ||
42 | TYPE_SCHAR, | ||
43 | TYPE_UCHAR, | ||
44 | TYPE_SHORT, | ||
45 | TYPE_USHORT, | ||
46 | TYPE_INT, | ||
47 | TYPE_UINT, | ||
48 | TYPE_LONGINT, | ||
49 | TYPE_ULONGINT, | ||
50 | #ifdef HAVE_LONG_LONG_INT | ||
51 | TYPE_LONGLONGINT, | ||
52 | TYPE_ULONGLONGINT, | ||
53 | #endif | ||
54 | TYPE_DOUBLE, | ||
55 | #ifdef HAVE_LONG_DOUBLE | ||
56 | TYPE_LONGDOUBLE, | ||
57 | #endif | ||
58 | TYPE_CHAR, | ||
59 | #ifdef HAVE_WINT_T | ||
60 | TYPE_WIDE_CHAR, | ||
61 | #endif | ||
62 | TYPE_STRING, | ||
63 | #ifdef HAVE_WCHAR_T | ||
64 | TYPE_WIDE_STRING, | ||
65 | #endif | ||
66 | TYPE_POINTER, | ||
67 | TYPE_COUNT_SCHAR_POINTER, | ||
68 | TYPE_COUNT_SHORT_POINTER, | ||
69 | TYPE_COUNT_INT_POINTER, | ||
70 | TYPE_COUNT_LONGINT_POINTER | ||
71 | #ifdef HAVE_LONG_LONG_INT | ||
72 | , TYPE_COUNT_LONGLONGINT_POINTER | ||
73 | #endif | ||
74 | } arg_type; | ||
75 | |||
76 | /* Polymorphic argument */ | ||
77 | typedef struct | ||
78 | { | ||
79 | arg_type type; | ||
80 | union | ||
81 | { | ||
82 | signed char a_schar; | ||
83 | unsigned char a_uchar; | ||
84 | short a_short; | ||
85 | unsigned short a_ushort; | ||
86 | int a_int; | ||
87 | unsigned int a_uint; | ||
88 | long int a_longint; | ||
89 | unsigned long int a_ulongint; | ||
90 | #ifdef HAVE_LONG_LONG_INT | ||
91 | long long int a_longlongint; | ||
92 | unsigned long long int a_ulonglongint; | ||
93 | #endif | ||
94 | float a_float; | ||
95 | double a_double; | ||
96 | #ifdef HAVE_LONG_DOUBLE | ||
97 | long double a_longdouble; | ||
98 | #endif | ||
99 | int a_char; | ||
100 | #ifdef HAVE_WINT_T | ||
101 | wint_t a_wide_char; | ||
102 | #endif | ||
103 | const char* a_string; | ||
104 | #ifdef HAVE_WCHAR_T | ||
105 | const wchar_t* a_wide_string; | ||
106 | #endif | ||
107 | void* a_pointer; | ||
108 | signed char * a_count_schar_pointer; | ||
109 | short * a_count_short_pointer; | ||
110 | int * a_count_int_pointer; | ||
111 | long int * a_count_longint_pointer; | ||
112 | #ifdef HAVE_LONG_LONG_INT | ||
113 | long long int * a_count_longlongint_pointer; | ||
114 | #endif | ||
115 | } | ||
116 | a; | ||
117 | } | ||
118 | argument; | ||
119 | |||
120 | typedef struct | ||
121 | { | ||
122 | size_t count; | ||
123 | argument *arg; | ||
124 | } | ||
125 | arguments; | ||
126 | |||
127 | |||
128 | /* Fetch the arguments, putting them into a. */ | ||
129 | #ifdef STATIC | ||
130 | STATIC | ||
131 | #else | ||
132 | extern | ||
133 | #endif | ||
134 | int printf_fetchargs (va_list args, arguments *a); | ||
135 | |||
136 | #endif /* _PRINTF_ARGS_H */ | ||
diff --git a/gl/printf-parse.c b/gl/printf-parse.c new file mode 100644 index 00000000..9a86f773 --- /dev/null +++ b/gl/printf-parse.c | |||
@@ -0,0 +1,543 @@ | |||
1 | /* Formatted output to strings. | ||
2 | Copyright (C) 1999-2000, 2002-2003, 2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #include <config.h> | ||
19 | |||
20 | /* Specification. */ | ||
21 | #if WIDE_CHAR_VERSION | ||
22 | # include "wprintf-parse.h" | ||
23 | #else | ||
24 | # include "printf-parse.h" | ||
25 | #endif | ||
26 | |||
27 | /* Get size_t, NULL. */ | ||
28 | #include <stddef.h> | ||
29 | |||
30 | /* Get intmax_t. */ | ||
31 | #if HAVE_STDINT_H_WITH_UINTMAX | ||
32 | # include <stdint.h> | ||
33 | #endif | ||
34 | #if HAVE_INTTYPES_H_WITH_UINTMAX | ||
35 | # include <inttypes.h> | ||
36 | #endif | ||
37 | |||
38 | /* malloc(), realloc(), free(). */ | ||
39 | #include <stdlib.h> | ||
40 | |||
41 | /* Checked size_t computations. */ | ||
42 | #include "xsize.h" | ||
43 | |||
44 | #if WIDE_CHAR_VERSION | ||
45 | # define PRINTF_PARSE wprintf_parse | ||
46 | # define CHAR_T wchar_t | ||
47 | # define DIRECTIVE wchar_t_directive | ||
48 | # define DIRECTIVES wchar_t_directives | ||
49 | #else | ||
50 | # define PRINTF_PARSE printf_parse | ||
51 | # define CHAR_T char | ||
52 | # define DIRECTIVE char_directive | ||
53 | # define DIRECTIVES char_directives | ||
54 | #endif | ||
55 | |||
56 | #ifdef STATIC | ||
57 | STATIC | ||
58 | #endif | ||
59 | int | ||
60 | PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) | ||
61 | { | ||
62 | const CHAR_T *cp = format; /* pointer into format */ | ||
63 | size_t arg_posn = 0; /* number of regular arguments consumed */ | ||
64 | size_t d_allocated; /* allocated elements of d->dir */ | ||
65 | size_t a_allocated; /* allocated elements of a->arg */ | ||
66 | size_t max_width_length = 0; | ||
67 | size_t max_precision_length = 0; | ||
68 | |||
69 | d->count = 0; | ||
70 | d_allocated = 1; | ||
71 | d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE)); | ||
72 | if (d->dir == NULL) | ||
73 | /* Out of memory. */ | ||
74 | return -1; | ||
75 | |||
76 | a->count = 0; | ||
77 | a_allocated = 0; | ||
78 | a->arg = NULL; | ||
79 | |||
80 | #define REGISTER_ARG(_index_,_type_) \ | ||
81 | { \ | ||
82 | size_t n = (_index_); \ | ||
83 | if (n >= a_allocated) \ | ||
84 | { \ | ||
85 | size_t memory_size; \ | ||
86 | argument *memory; \ | ||
87 | \ | ||
88 | a_allocated = xtimes (a_allocated, 2); \ | ||
89 | if (a_allocated <= n) \ | ||
90 | a_allocated = xsum (n, 1); \ | ||
91 | memory_size = xtimes (a_allocated, sizeof (argument)); \ | ||
92 | if (size_overflow_p (memory_size)) \ | ||
93 | /* Overflow, would lead to out of memory. */ \ | ||
94 | goto error; \ | ||
95 | memory = (argument *) (a->arg \ | ||
96 | ? realloc (a->arg, memory_size) \ | ||
97 | : malloc (memory_size)); \ | ||
98 | if (memory == NULL) \ | ||
99 | /* Out of memory. */ \ | ||
100 | goto error; \ | ||
101 | a->arg = memory; \ | ||
102 | } \ | ||
103 | while (a->count <= n) \ | ||
104 | a->arg[a->count++].type = TYPE_NONE; \ | ||
105 | if (a->arg[n].type == TYPE_NONE) \ | ||
106 | a->arg[n].type = (_type_); \ | ||
107 | else if (a->arg[n].type != (_type_)) \ | ||
108 | /* Ambiguous type for positional argument. */ \ | ||
109 | goto error; \ | ||
110 | } | ||
111 | |||
112 | while (*cp != '\0') | ||
113 | { | ||
114 | CHAR_T c = *cp++; | ||
115 | if (c == '%') | ||
116 | { | ||
117 | size_t arg_index = ARG_NONE; | ||
118 | DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */ | ||
119 | |||
120 | /* Initialize the next directive. */ | ||
121 | dp->dir_start = cp - 1; | ||
122 | dp->flags = 0; | ||
123 | dp->width_start = NULL; | ||
124 | dp->width_end = NULL; | ||
125 | dp->width_arg_index = ARG_NONE; | ||
126 | dp->precision_start = NULL; | ||
127 | dp->precision_end = NULL; | ||
128 | dp->precision_arg_index = ARG_NONE; | ||
129 | dp->arg_index = ARG_NONE; | ||
130 | |||
131 | /* Test for positional argument. */ | ||
132 | if (*cp >= '0' && *cp <= '9') | ||
133 | { | ||
134 | const CHAR_T *np; | ||
135 | |||
136 | for (np = cp; *np >= '0' && *np <= '9'; np++) | ||
137 | ; | ||
138 | if (*np == '$') | ||
139 | { | ||
140 | size_t n = 0; | ||
141 | |||
142 | for (np = cp; *np >= '0' && *np <= '9'; np++) | ||
143 | n = xsum (xtimes (n, 10), *np - '0'); | ||
144 | if (n == 0) | ||
145 | /* Positional argument 0. */ | ||
146 | goto error; | ||
147 | if (size_overflow_p (n)) | ||
148 | /* n too large, would lead to out of memory later. */ | ||
149 | goto error; | ||
150 | arg_index = n - 1; | ||
151 | cp = np + 1; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | /* Read the flags. */ | ||
156 | for (;;) | ||
157 | { | ||
158 | if (*cp == '\'') | ||
159 | { | ||
160 | dp->flags |= FLAG_GROUP; | ||
161 | cp++; | ||
162 | } | ||
163 | else if (*cp == '-') | ||
164 | { | ||
165 | dp->flags |= FLAG_LEFT; | ||
166 | cp++; | ||
167 | } | ||
168 | else if (*cp == '+') | ||
169 | { | ||
170 | dp->flags |= FLAG_SHOWSIGN; | ||
171 | cp++; | ||
172 | } | ||
173 | else if (*cp == ' ') | ||
174 | { | ||
175 | dp->flags |= FLAG_SPACE; | ||
176 | cp++; | ||
177 | } | ||
178 | else if (*cp == '#') | ||
179 | { | ||
180 | dp->flags |= FLAG_ALT; | ||
181 | cp++; | ||
182 | } | ||
183 | else if (*cp == '0') | ||
184 | { | ||
185 | dp->flags |= FLAG_ZERO; | ||
186 | cp++; | ||
187 | } | ||
188 | else | ||
189 | break; | ||
190 | } | ||
191 | |||
192 | /* Parse the field width. */ | ||
193 | if (*cp == '*') | ||
194 | { | ||
195 | dp->width_start = cp; | ||
196 | cp++; | ||
197 | dp->width_end = cp; | ||
198 | if (max_width_length < 1) | ||
199 | max_width_length = 1; | ||
200 | |||
201 | /* Test for positional argument. */ | ||
202 | if (*cp >= '0' && *cp <= '9') | ||
203 | { | ||
204 | const CHAR_T *np; | ||
205 | |||
206 | for (np = cp; *np >= '0' && *np <= '9'; np++) | ||
207 | ; | ||
208 | if (*np == '$') | ||
209 | { | ||
210 | size_t n = 0; | ||
211 | |||
212 | for (np = cp; *np >= '0' && *np <= '9'; np++) | ||
213 | n = xsum (xtimes (n, 10), *np - '0'); | ||
214 | if (n == 0) | ||
215 | /* Positional argument 0. */ | ||
216 | goto error; | ||
217 | if (size_overflow_p (n)) | ||
218 | /* n too large, would lead to out of memory later. */ | ||
219 | goto error; | ||
220 | dp->width_arg_index = n - 1; | ||
221 | cp = np + 1; | ||
222 | } | ||
223 | } | ||
224 | if (dp->width_arg_index == ARG_NONE) | ||
225 | { | ||
226 | dp->width_arg_index = arg_posn++; | ||
227 | if (dp->width_arg_index == ARG_NONE) | ||
228 | /* arg_posn wrapped around. */ | ||
229 | goto error; | ||
230 | } | ||
231 | REGISTER_ARG (dp->width_arg_index, TYPE_INT); | ||
232 | } | ||
233 | else if (*cp >= '0' && *cp <= '9') | ||
234 | { | ||
235 | size_t width_length; | ||
236 | |||
237 | dp->width_start = cp; | ||
238 | for (; *cp >= '0' && *cp <= '9'; cp++) | ||
239 | ; | ||
240 | dp->width_end = cp; | ||
241 | width_length = dp->width_end - dp->width_start; | ||
242 | if (max_width_length < width_length) | ||
243 | max_width_length = width_length; | ||
244 | } | ||
245 | |||
246 | /* Parse the precision. */ | ||
247 | if (*cp == '.') | ||
248 | { | ||
249 | cp++; | ||
250 | if (*cp == '*') | ||
251 | { | ||
252 | dp->precision_start = cp - 1; | ||
253 | cp++; | ||
254 | dp->precision_end = cp; | ||
255 | if (max_precision_length < 2) | ||
256 | max_precision_length = 2; | ||
257 | |||
258 | /* Test for positional argument. */ | ||
259 | if (*cp >= '0' && *cp <= '9') | ||
260 | { | ||
261 | const CHAR_T *np; | ||
262 | |||
263 | for (np = cp; *np >= '0' && *np <= '9'; np++) | ||
264 | ; | ||
265 | if (*np == '$') | ||
266 | { | ||
267 | size_t n = 0; | ||
268 | |||
269 | for (np = cp; *np >= '0' && *np <= '9'; np++) | ||
270 | n = xsum (xtimes (n, 10), *np - '0'); | ||
271 | if (n == 0) | ||
272 | /* Positional argument 0. */ | ||
273 | goto error; | ||
274 | if (size_overflow_p (n)) | ||
275 | /* n too large, would lead to out of memory | ||
276 | later. */ | ||
277 | goto error; | ||
278 | dp->precision_arg_index = n - 1; | ||
279 | cp = np + 1; | ||
280 | } | ||
281 | } | ||
282 | if (dp->precision_arg_index == ARG_NONE) | ||
283 | { | ||
284 | dp->precision_arg_index = arg_posn++; | ||
285 | if (dp->precision_arg_index == ARG_NONE) | ||
286 | /* arg_posn wrapped around. */ | ||
287 | goto error; | ||
288 | } | ||
289 | REGISTER_ARG (dp->precision_arg_index, TYPE_INT); | ||
290 | } | ||
291 | else | ||
292 | { | ||
293 | size_t precision_length; | ||
294 | |||
295 | dp->precision_start = cp - 1; | ||
296 | for (; *cp >= '0' && *cp <= '9'; cp++) | ||
297 | ; | ||
298 | dp->precision_end = cp; | ||
299 | precision_length = dp->precision_end - dp->precision_start; | ||
300 | if (max_precision_length < precision_length) | ||
301 | max_precision_length = precision_length; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | { | ||
306 | arg_type type; | ||
307 | |||
308 | /* Parse argument type/size specifiers. */ | ||
309 | { | ||
310 | int flags = 0; | ||
311 | |||
312 | for (;;) | ||
313 | { | ||
314 | if (*cp == 'h') | ||
315 | { | ||
316 | flags |= (1 << (flags & 1)); | ||
317 | cp++; | ||
318 | } | ||
319 | else if (*cp == 'L') | ||
320 | { | ||
321 | flags |= 4; | ||
322 | cp++; | ||
323 | } | ||
324 | else if (*cp == 'l') | ||
325 | { | ||
326 | flags += 8; | ||
327 | cp++; | ||
328 | } | ||
329 | #ifdef HAVE_INTMAX_T | ||
330 | else if (*cp == 'j') | ||
331 | { | ||
332 | if (sizeof (intmax_t) > sizeof (long)) | ||
333 | { | ||
334 | /* intmax_t = long long */ | ||
335 | flags += 16; | ||
336 | } | ||
337 | else if (sizeof (intmax_t) > sizeof (int)) | ||
338 | { | ||
339 | /* intmax_t = long */ | ||
340 | flags += 8; | ||
341 | } | ||
342 | cp++; | ||
343 | } | ||
344 | #endif | ||
345 | else if (*cp == 'z' || *cp == 'Z') | ||
346 | { | ||
347 | /* 'z' is standardized in ISO C 99, but glibc uses 'Z' | ||
348 | because the warning facility in gcc-2.95.2 understands | ||
349 | only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */ | ||
350 | if (sizeof (size_t) > sizeof (long)) | ||
351 | { | ||
352 | /* size_t = long long */ | ||
353 | flags += 16; | ||
354 | } | ||
355 | else if (sizeof (size_t) > sizeof (int)) | ||
356 | { | ||
357 | /* size_t = long */ | ||
358 | flags += 8; | ||
359 | } | ||
360 | cp++; | ||
361 | } | ||
362 | else if (*cp == 't') | ||
363 | { | ||
364 | if (sizeof (ptrdiff_t) > sizeof (long)) | ||
365 | { | ||
366 | /* ptrdiff_t = long long */ | ||
367 | flags += 16; | ||
368 | } | ||
369 | else if (sizeof (ptrdiff_t) > sizeof (int)) | ||
370 | { | ||
371 | /* ptrdiff_t = long */ | ||
372 | flags += 8; | ||
373 | } | ||
374 | cp++; | ||
375 | } | ||
376 | else | ||
377 | break; | ||
378 | } | ||
379 | |||
380 | /* Read the conversion character. */ | ||
381 | c = *cp++; | ||
382 | switch (c) | ||
383 | { | ||
384 | case 'd': case 'i': | ||
385 | #ifdef HAVE_LONG_LONG_INT | ||
386 | /* If 'long long' exists and is larger than 'long': */ | ||
387 | if (flags >= 16 || (flags & 4)) | ||
388 | type = TYPE_LONGLONGINT; | ||
389 | else | ||
390 | #endif | ||
391 | /* If 'long long' exists and is the same as 'long', we parse | ||
392 | "lld" into TYPE_LONGINT. */ | ||
393 | if (flags >= 8) | ||
394 | type = TYPE_LONGINT; | ||
395 | else if (flags & 2) | ||
396 | type = TYPE_SCHAR; | ||
397 | else if (flags & 1) | ||
398 | type = TYPE_SHORT; | ||
399 | else | ||
400 | type = TYPE_INT; | ||
401 | break; | ||
402 | case 'o': case 'u': case 'x': case 'X': | ||
403 | #ifdef HAVE_LONG_LONG_INT | ||
404 | /* If 'long long' exists and is larger than 'long': */ | ||
405 | if (flags >= 16 || (flags & 4)) | ||
406 | type = TYPE_ULONGLONGINT; | ||
407 | else | ||
408 | #endif | ||
409 | /* If 'unsigned long long' exists and is the same as | ||
410 | 'unsigned long', we parse "llu" into TYPE_ULONGINT. */ | ||
411 | if (flags >= 8) | ||
412 | type = TYPE_ULONGINT; | ||
413 | else if (flags & 2) | ||
414 | type = TYPE_UCHAR; | ||
415 | else if (flags & 1) | ||
416 | type = TYPE_USHORT; | ||
417 | else | ||
418 | type = TYPE_UINT; | ||
419 | break; | ||
420 | case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': | ||
421 | case 'a': case 'A': | ||
422 | #ifdef HAVE_LONG_DOUBLE | ||
423 | if (flags >= 16 || (flags & 4)) | ||
424 | type = TYPE_LONGDOUBLE; | ||
425 | else | ||
426 | #endif | ||
427 | type = TYPE_DOUBLE; | ||
428 | break; | ||
429 | case 'c': | ||
430 | if (flags >= 8) | ||
431 | #ifdef HAVE_WINT_T | ||
432 | type = TYPE_WIDE_CHAR; | ||
433 | #else | ||
434 | goto error; | ||
435 | #endif | ||
436 | else | ||
437 | type = TYPE_CHAR; | ||
438 | break; | ||
439 | #ifdef HAVE_WINT_T | ||
440 | case 'C': | ||
441 | type = TYPE_WIDE_CHAR; | ||
442 | c = 'c'; | ||
443 | break; | ||
444 | #endif | ||
445 | case 's': | ||
446 | if (flags >= 8) | ||
447 | #ifdef HAVE_WCHAR_T | ||
448 | type = TYPE_WIDE_STRING; | ||
449 | #else | ||
450 | goto error; | ||
451 | #endif | ||
452 | else | ||
453 | type = TYPE_STRING; | ||
454 | break; | ||
455 | #ifdef HAVE_WCHAR_T | ||
456 | case 'S': | ||
457 | type = TYPE_WIDE_STRING; | ||
458 | c = 's'; | ||
459 | break; | ||
460 | #endif | ||
461 | case 'p': | ||
462 | type = TYPE_POINTER; | ||
463 | break; | ||
464 | case 'n': | ||
465 | #ifdef HAVE_LONG_LONG_INT | ||
466 | /* If 'long long' exists and is larger than 'long': */ | ||
467 | if (flags >= 16 || (flags & 4)) | ||
468 | type = TYPE_COUNT_LONGLONGINT_POINTER; | ||
469 | else | ||
470 | #endif | ||
471 | /* If 'long long' exists and is the same as 'long', we parse | ||
472 | "lln" into TYPE_COUNT_LONGINT_POINTER. */ | ||
473 | if (flags >= 8) | ||
474 | type = TYPE_COUNT_LONGINT_POINTER; | ||
475 | else if (flags & 2) | ||
476 | type = TYPE_COUNT_SCHAR_POINTER; | ||
477 | else if (flags & 1) | ||
478 | type = TYPE_COUNT_SHORT_POINTER; | ||
479 | else | ||
480 | type = TYPE_COUNT_INT_POINTER; | ||
481 | break; | ||
482 | case '%': | ||
483 | type = TYPE_NONE; | ||
484 | break; | ||
485 | default: | ||
486 | /* Unknown conversion character. */ | ||
487 | goto error; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | if (type != TYPE_NONE) | ||
492 | { | ||
493 | dp->arg_index = arg_index; | ||
494 | if (dp->arg_index == ARG_NONE) | ||
495 | { | ||
496 | dp->arg_index = arg_posn++; | ||
497 | if (dp->arg_index == ARG_NONE) | ||
498 | /* arg_posn wrapped around. */ | ||
499 | goto error; | ||
500 | } | ||
501 | REGISTER_ARG (dp->arg_index, type); | ||
502 | } | ||
503 | dp->conversion = c; | ||
504 | dp->dir_end = cp; | ||
505 | } | ||
506 | |||
507 | d->count++; | ||
508 | if (d->count >= d_allocated) | ||
509 | { | ||
510 | size_t memory_size; | ||
511 | DIRECTIVE *memory; | ||
512 | |||
513 | d_allocated = xtimes (d_allocated, 2); | ||
514 | memory_size = xtimes (d_allocated, sizeof (DIRECTIVE)); | ||
515 | if (size_overflow_p (memory_size)) | ||
516 | /* Overflow, would lead to out of memory. */ | ||
517 | goto error; | ||
518 | memory = (DIRECTIVE *) realloc (d->dir, memory_size); | ||
519 | if (memory == NULL) | ||
520 | /* Out of memory. */ | ||
521 | goto error; | ||
522 | d->dir = memory; | ||
523 | } | ||
524 | } | ||
525 | } | ||
526 | d->dir[d->count].dir_start = cp; | ||
527 | |||
528 | d->max_width_length = max_width_length; | ||
529 | d->max_precision_length = max_precision_length; | ||
530 | return 0; | ||
531 | |||
532 | error: | ||
533 | if (a->arg) | ||
534 | free (a->arg); | ||
535 | if (d->dir) | ||
536 | free (d->dir); | ||
537 | return -1; | ||
538 | } | ||
539 | |||
540 | #undef DIRECTIVES | ||
541 | #undef DIRECTIVE | ||
542 | #undef CHAR_T | ||
543 | #undef PRINTF_PARSE | ||
diff --git a/gl/printf-parse.h b/gl/printf-parse.h new file mode 100644 index 00000000..82a0d37c --- /dev/null +++ b/gl/printf-parse.h | |||
@@ -0,0 +1,74 @@ | |||
1 | /* Parse printf format string. | ||
2 | Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _PRINTF_PARSE_H | ||
19 | #define _PRINTF_PARSE_H | ||
20 | |||
21 | #include "printf-args.h" | ||
22 | |||
23 | |||
24 | /* Flags */ | ||
25 | #define FLAG_GROUP 1 /* ' flag */ | ||
26 | #define FLAG_LEFT 2 /* - flag */ | ||
27 | #define FLAG_SHOWSIGN 4 /* + flag */ | ||
28 | #define FLAG_SPACE 8 /* space flag */ | ||
29 | #define FLAG_ALT 16 /* # flag */ | ||
30 | #define FLAG_ZERO 32 | ||
31 | |||
32 | /* arg_index value indicating that no argument is consumed. */ | ||
33 | #define ARG_NONE (~(size_t)0) | ||
34 | |||
35 | /* A parsed directive. */ | ||
36 | typedef struct | ||
37 | { | ||
38 | const char* dir_start; | ||
39 | const char* dir_end; | ||
40 | int flags; | ||
41 | const char* width_start; | ||
42 | const char* width_end; | ||
43 | size_t width_arg_index; | ||
44 | const char* precision_start; | ||
45 | const char* precision_end; | ||
46 | size_t precision_arg_index; | ||
47 | char conversion; /* d i o u x X f e E g G c s p n U % but not C S */ | ||
48 | size_t arg_index; | ||
49 | } | ||
50 | char_directive; | ||
51 | |||
52 | /* A parsed format string. */ | ||
53 | typedef struct | ||
54 | { | ||
55 | size_t count; | ||
56 | char_directive *dir; | ||
57 | size_t max_width_length; | ||
58 | size_t max_precision_length; | ||
59 | } | ||
60 | char_directives; | ||
61 | |||
62 | |||
63 | /* Parses the format string. Fills in the number N of directives, and fills | ||
64 | in directives[0], ..., directives[N-1], and sets directives[N].dir_start | ||
65 | to the end of the format string. Also fills in the arg_type fields of the | ||
66 | arguments and the needed count of arguments. */ | ||
67 | #ifdef STATIC | ||
68 | STATIC | ||
69 | #else | ||
70 | extern | ||
71 | #endif | ||
72 | int printf_parse (const char *format, char_directives *d, arguments *a); | ||
73 | |||
74 | #endif /* _PRINTF_PARSE_H */ | ||
diff --git a/gl/regcomp.c b/gl/regcomp.c new file mode 100644 index 00000000..8df6bb80 --- /dev/null +++ b/gl/regcomp.c | |||
@@ -0,0 +1,3858 @@ | |||
1 | /* Extended regular expression matching and search library. | ||
2 | Copyright (C) 2002,2003,2004,2005,2006 Free Software Foundation, Inc. | ||
3 | This file is part of the GNU C Library. | ||
4 | Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License along | ||
17 | with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, | ||
21 | size_t length, reg_syntax_t syntax); | ||
22 | static void re_compile_fastmap_iter (regex_t *bufp, | ||
23 | const re_dfastate_t *init_state, | ||
24 | char *fastmap); | ||
25 | static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len); | ||
26 | #ifdef RE_ENABLE_I18N | ||
27 | static void free_charset (re_charset_t *cset); | ||
28 | #endif /* RE_ENABLE_I18N */ | ||
29 | static void free_workarea_compile (regex_t *preg); | ||
30 | static reg_errcode_t create_initial_state (re_dfa_t *dfa); | ||
31 | #ifdef RE_ENABLE_I18N | ||
32 | static void optimize_utf8 (re_dfa_t *dfa); | ||
33 | #endif | ||
34 | static reg_errcode_t analyze (regex_t *preg); | ||
35 | static reg_errcode_t preorder (bin_tree_t *root, | ||
36 | reg_errcode_t (fn (void *, bin_tree_t *)), | ||
37 | void *extra); | ||
38 | static reg_errcode_t postorder (bin_tree_t *root, | ||
39 | reg_errcode_t (fn (void *, bin_tree_t *)), | ||
40 | void *extra); | ||
41 | static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node); | ||
42 | static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node); | ||
43 | static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg, | ||
44 | bin_tree_t *node); | ||
45 | static reg_errcode_t calc_first (void *extra, bin_tree_t *node); | ||
46 | static reg_errcode_t calc_next (void *extra, bin_tree_t *node); | ||
47 | static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node); | ||
48 | static Idx duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int constraint); | ||
49 | static Idx search_duplicated_node (const re_dfa_t *dfa, Idx org_node, | ||
50 | unsigned int constraint); | ||
51 | static reg_errcode_t calc_eclosure (re_dfa_t *dfa); | ||
52 | static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, | ||
53 | Idx node, bool root); | ||
54 | static reg_errcode_t calc_inveclosure (re_dfa_t *dfa); | ||
55 | static Idx fetch_number (re_string_t *input, re_token_t *token, | ||
56 | reg_syntax_t syntax); | ||
57 | static int peek_token (re_token_t *token, re_string_t *input, | ||
58 | reg_syntax_t syntax) internal_function; | ||
59 | static bin_tree_t *parse (re_string_t *regexp, regex_t *preg, | ||
60 | reg_syntax_t syntax, reg_errcode_t *err); | ||
61 | static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg, | ||
62 | re_token_t *token, reg_syntax_t syntax, | ||
63 | Idx nest, reg_errcode_t *err); | ||
64 | static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg, | ||
65 | re_token_t *token, reg_syntax_t syntax, | ||
66 | Idx nest, reg_errcode_t *err); | ||
67 | static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg, | ||
68 | re_token_t *token, reg_syntax_t syntax, | ||
69 | Idx nest, reg_errcode_t *err); | ||
70 | static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg, | ||
71 | re_token_t *token, reg_syntax_t syntax, | ||
72 | Idx nest, reg_errcode_t *err); | ||
73 | static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp, | ||
74 | re_dfa_t *dfa, re_token_t *token, | ||
75 | reg_syntax_t syntax, reg_errcode_t *err); | ||
76 | static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, | ||
77 | re_token_t *token, reg_syntax_t syntax, | ||
78 | reg_errcode_t *err); | ||
79 | static reg_errcode_t parse_bracket_element (bracket_elem_t *elem, | ||
80 | re_string_t *regexp, | ||
81 | re_token_t *token, int token_len, | ||
82 | re_dfa_t *dfa, | ||
83 | reg_syntax_t syntax, | ||
84 | bool accept_hyphen); | ||
85 | static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem, | ||
86 | re_string_t *regexp, | ||
87 | re_token_t *token); | ||
88 | #ifdef RE_ENABLE_I18N | ||
89 | static reg_errcode_t build_equiv_class (bitset_t sbcset, | ||
90 | re_charset_t *mbcset, | ||
91 | Idx *equiv_class_alloc, | ||
92 | const unsigned char *name); | ||
93 | static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans, | ||
94 | bitset_t sbcset, | ||
95 | re_charset_t *mbcset, | ||
96 | Idx *char_class_alloc, | ||
97 | const unsigned char *class_name, | ||
98 | reg_syntax_t syntax); | ||
99 | #else /* not RE_ENABLE_I18N */ | ||
100 | static reg_errcode_t build_equiv_class (bitset_t sbcset, | ||
101 | const unsigned char *name); | ||
102 | static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans, | ||
103 | bitset_t sbcset, | ||
104 | const unsigned char *class_name, | ||
105 | reg_syntax_t syntax); | ||
106 | #endif /* not RE_ENABLE_I18N */ | ||
107 | static bin_tree_t *build_charclass_op (re_dfa_t *dfa, | ||
108 | RE_TRANSLATE_TYPE trans, | ||
109 | const unsigned char *class_name, | ||
110 | const unsigned char *extra, | ||
111 | bool non_match, reg_errcode_t *err); | ||
112 | static bin_tree_t *create_tree (re_dfa_t *dfa, | ||
113 | bin_tree_t *left, bin_tree_t *right, | ||
114 | re_token_type_t type); | ||
115 | static bin_tree_t *create_token_tree (re_dfa_t *dfa, | ||
116 | bin_tree_t *left, bin_tree_t *right, | ||
117 | const re_token_t *token); | ||
118 | static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa); | ||
119 | static void free_token (re_token_t *node); | ||
120 | static reg_errcode_t free_tree (void *extra, bin_tree_t *node); | ||
121 | static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node); | ||
122 | |||
123 | /* This table gives an error message for each of the error codes listed | ||
124 | in regex.h. Obviously the order here has to be same as there. | ||
125 | POSIX doesn't require that we do anything for REG_NOERROR, | ||
126 | but why not be nice? */ | ||
127 | |||
128 | static const char __re_error_msgid[] = | ||
129 | { | ||
130 | #define REG_NOERROR_IDX 0 | ||
131 | gettext_noop ("Success") /* REG_NOERROR */ | ||
132 | "\0" | ||
133 | #define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") | ||
134 | gettext_noop ("No match") /* REG_NOMATCH */ | ||
135 | "\0" | ||
136 | #define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") | ||
137 | gettext_noop ("Invalid regular expression") /* REG_BADPAT */ | ||
138 | "\0" | ||
139 | #define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") | ||
140 | gettext_noop ("Invalid collation character") /* REG_ECOLLATE */ | ||
141 | "\0" | ||
142 | #define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") | ||
143 | gettext_noop ("Invalid character class name") /* REG_ECTYPE */ | ||
144 | "\0" | ||
145 | #define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") | ||
146 | gettext_noop ("Trailing backslash") /* REG_EESCAPE */ | ||
147 | "\0" | ||
148 | #define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") | ||
149 | gettext_noop ("Invalid back reference") /* REG_ESUBREG */ | ||
150 | "\0" | ||
151 | #define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") | ||
152 | gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */ | ||
153 | "\0" | ||
154 | #define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^") | ||
155 | gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ | ||
156 | "\0" | ||
157 | #define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") | ||
158 | gettext_noop ("Unmatched \\{") /* REG_EBRACE */ | ||
159 | "\0" | ||
160 | #define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") | ||
161 | gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ | ||
162 | "\0" | ||
163 | #define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") | ||
164 | gettext_noop ("Invalid range end") /* REG_ERANGE */ | ||
165 | "\0" | ||
166 | #define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") | ||
167 | gettext_noop ("Memory exhausted") /* REG_ESPACE */ | ||
168 | "\0" | ||
169 | #define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") | ||
170 | gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ | ||
171 | "\0" | ||
172 | #define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") | ||
173 | gettext_noop ("Premature end of regular expression") /* REG_EEND */ | ||
174 | "\0" | ||
175 | #define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") | ||
176 | gettext_noop ("Regular expression too big") /* REG_ESIZE */ | ||
177 | "\0" | ||
178 | #define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") | ||
179 | gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ | ||
180 | }; | ||
181 | |||
182 | static const size_t __re_error_msgid_idx[] = | ||
183 | { | ||
184 | REG_NOERROR_IDX, | ||
185 | REG_NOMATCH_IDX, | ||
186 | REG_BADPAT_IDX, | ||
187 | REG_ECOLLATE_IDX, | ||
188 | REG_ECTYPE_IDX, | ||
189 | REG_EESCAPE_IDX, | ||
190 | REG_ESUBREG_IDX, | ||
191 | REG_EBRACK_IDX, | ||
192 | REG_EPAREN_IDX, | ||
193 | REG_EBRACE_IDX, | ||
194 | REG_BADBR_IDX, | ||
195 | REG_ERANGE_IDX, | ||
196 | REG_ESPACE_IDX, | ||
197 | REG_BADRPT_IDX, | ||
198 | REG_EEND_IDX, | ||
199 | REG_ESIZE_IDX, | ||
200 | REG_ERPAREN_IDX | ||
201 | }; | ||
202 | |||
203 | /* Entry points for GNU code. */ | ||
204 | |||
205 | /* re_compile_pattern is the GNU regular expression compiler: it | ||
206 | compiles PATTERN (of length LENGTH) and puts the result in BUFP. | ||
207 | Returns 0 if the pattern was valid, otherwise an error string. | ||
208 | |||
209 | Assumes the `allocated' (and perhaps `buffer') and `translate' fields | ||
210 | are set in BUFP on entry. */ | ||
211 | |||
212 | #ifdef _LIBC | ||
213 | const char * | ||
214 | re_compile_pattern (pattern, length, bufp) | ||
215 | const char *pattern; | ||
216 | size_t length; | ||
217 | struct re_pattern_buffer *bufp; | ||
218 | #else /* size_t might promote */ | ||
219 | const char * | ||
220 | re_compile_pattern (const char *pattern, size_t length, | ||
221 | struct re_pattern_buffer *bufp) | ||
222 | #endif | ||
223 | { | ||
224 | reg_errcode_t ret; | ||
225 | |||
226 | /* And GNU code determines whether or not to get register information | ||
227 | by passing null for the REGS argument to re_match, etc., not by | ||
228 | setting no_sub, unless RE_NO_SUB is set. */ | ||
229 | bufp->no_sub = !!(re_syntax_options & RE_NO_SUB); | ||
230 | |||
231 | /* Match anchors at newline. */ | ||
232 | bufp->newline_anchor = 1; | ||
233 | |||
234 | ret = re_compile_internal (bufp, pattern, length, re_syntax_options); | ||
235 | |||
236 | if (!ret) | ||
237 | return NULL; | ||
238 | return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); | ||
239 | } | ||
240 | #ifdef _LIBC | ||
241 | weak_alias (__re_compile_pattern, re_compile_pattern) | ||
242 | #endif | ||
243 | |||
244 | /* Set by `re_set_syntax' to the current regexp syntax to recognize. Can | ||
245 | also be assigned to arbitrarily: each pattern buffer stores its own | ||
246 | syntax, so it can be changed between regex compilations. */ | ||
247 | /* This has no initializer because initialized variables in Emacs | ||
248 | become read-only after dumping. */ | ||
249 | reg_syntax_t re_syntax_options; | ||
250 | |||
251 | |||
252 | /* Specify the precise syntax of regexps for compilation. This provides | ||
253 | for compatibility for various utilities which historically have | ||
254 | different, incompatible syntaxes. | ||
255 | |||
256 | The argument SYNTAX is a bit mask comprised of the various bits | ||
257 | defined in regex.h. We return the old syntax. */ | ||
258 | |||
259 | reg_syntax_t | ||
260 | re_set_syntax (syntax) | ||
261 | reg_syntax_t syntax; | ||
262 | { | ||
263 | reg_syntax_t ret = re_syntax_options; | ||
264 | |||
265 | re_syntax_options = syntax; | ||
266 | return ret; | ||
267 | } | ||
268 | #ifdef _LIBC | ||
269 | weak_alias (__re_set_syntax, re_set_syntax) | ||
270 | #endif | ||
271 | |||
272 | int | ||
273 | re_compile_fastmap (bufp) | ||
274 | struct re_pattern_buffer *bufp; | ||
275 | { | ||
276 | re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; | ||
277 | char *fastmap = bufp->fastmap; | ||
278 | |||
279 | memset (fastmap, '\0', sizeof (char) * SBC_MAX); | ||
280 | re_compile_fastmap_iter (bufp, dfa->init_state, fastmap); | ||
281 | if (dfa->init_state != dfa->init_state_word) | ||
282 | re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap); | ||
283 | if (dfa->init_state != dfa->init_state_nl) | ||
284 | re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap); | ||
285 | if (dfa->init_state != dfa->init_state_begbuf) | ||
286 | re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap); | ||
287 | bufp->fastmap_accurate = 1; | ||
288 | return 0; | ||
289 | } | ||
290 | #ifdef _LIBC | ||
291 | weak_alias (__re_compile_fastmap, re_compile_fastmap) | ||
292 | #endif | ||
293 | |||
294 | static inline void | ||
295 | __attribute ((always_inline)) | ||
296 | re_set_fastmap (char *fastmap, bool icase, int ch) | ||
297 | { | ||
298 | fastmap[ch] = 1; | ||
299 | if (icase) | ||
300 | fastmap[tolower (ch)] = 1; | ||
301 | } | ||
302 | |||
303 | /* Helper function for re_compile_fastmap. | ||
304 | Compile fastmap for the initial_state INIT_STATE. */ | ||
305 | |||
306 | static void | ||
307 | re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, | ||
308 | char *fastmap) | ||
309 | { | ||
310 | re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; | ||
311 | Idx node_cnt; | ||
312 | bool icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE)); | ||
313 | for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) | ||
314 | { | ||
315 | Idx node = init_state->nodes.elems[node_cnt]; | ||
316 | re_token_type_t type = dfa->nodes[node].type; | ||
317 | |||
318 | if (type == CHARACTER) | ||
319 | { | ||
320 | re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c); | ||
321 | #ifdef RE_ENABLE_I18N | ||
322 | if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) | ||
323 | { | ||
324 | unsigned char buf[MB_LEN_MAX]; | ||
325 | unsigned char *p; | ||
326 | wchar_t wc; | ||
327 | mbstate_t state; | ||
328 | |||
329 | p = buf; | ||
330 | *p++ = dfa->nodes[node].opr.c; | ||
331 | while (++node < dfa->nodes_len | ||
332 | && dfa->nodes[node].type == CHARACTER | ||
333 | && dfa->nodes[node].mb_partial) | ||
334 | *p++ = dfa->nodes[node].opr.c; | ||
335 | memset (&state, '\0', sizeof (state)); | ||
336 | if (mbrtowc (&wc, (const char *) buf, p - buf, | ||
337 | &state) == p - buf | ||
338 | && (__wcrtomb ((char *) buf, towlower (wc), &state) | ||
339 | != (size_t) -1)) | ||
340 | re_set_fastmap (fastmap, false, buf[0]); | ||
341 | } | ||
342 | #endif | ||
343 | } | ||
344 | else if (type == SIMPLE_BRACKET) | ||
345 | { | ||
346 | int i, ch; | ||
347 | for (i = 0, ch = 0; i < BITSET_WORDS; ++i) | ||
348 | { | ||
349 | int j; | ||
350 | bitset_word_t w = dfa->nodes[node].opr.sbcset[i]; | ||
351 | for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) | ||
352 | if (w & ((bitset_word_t) 1 << j)) | ||
353 | re_set_fastmap (fastmap, icase, ch); | ||
354 | } | ||
355 | } | ||
356 | #ifdef RE_ENABLE_I18N | ||
357 | else if (type == COMPLEX_BRACKET) | ||
358 | { | ||
359 | Idx i; | ||
360 | re_charset_t *cset = dfa->nodes[node].opr.mbcset; | ||
361 | if (cset->non_match || cset->ncoll_syms || cset->nequiv_classes | ||
362 | || cset->nranges || cset->nchar_classes) | ||
363 | { | ||
364 | # ifdef _LIBC | ||
365 | if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0) | ||
366 | { | ||
367 | /* In this case we want to catch the bytes which are | ||
368 | the first byte of any collation elements. | ||
369 | e.g. In da_DK, we want to catch 'a' since "aa" | ||
370 | is a valid collation element, and don't catch | ||
371 | 'b' since 'b' is the only collation element | ||
372 | which starts from 'b'. */ | ||
373 | const int32_t *table = (const int32_t *) | ||
374 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); | ||
375 | for (i = 0; i < SBC_MAX; ++i) | ||
376 | if (table[i] < 0) | ||
377 | re_set_fastmap (fastmap, icase, i); | ||
378 | } | ||
379 | # else | ||
380 | if (dfa->mb_cur_max > 1) | ||
381 | for (i = 0; i < SBC_MAX; ++i) | ||
382 | if (__btowc (i) == WEOF) | ||
383 | re_set_fastmap (fastmap, icase, i); | ||
384 | # endif /* not _LIBC */ | ||
385 | } | ||
386 | for (i = 0; i < cset->nmbchars; ++i) | ||
387 | { | ||
388 | char buf[256]; | ||
389 | mbstate_t state; | ||
390 | memset (&state, '\0', sizeof (state)); | ||
391 | if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1) | ||
392 | re_set_fastmap (fastmap, icase, *(unsigned char *) buf); | ||
393 | if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) | ||
394 | { | ||
395 | if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state) | ||
396 | != (size_t) -1) | ||
397 | re_set_fastmap (fastmap, false, *(unsigned char *) buf); | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | #endif /* RE_ENABLE_I18N */ | ||
402 | else if (type == OP_PERIOD | ||
403 | #ifdef RE_ENABLE_I18N | ||
404 | || type == OP_UTF8_PERIOD | ||
405 | #endif /* RE_ENABLE_I18N */ | ||
406 | || type == END_OF_RE) | ||
407 | { | ||
408 | memset (fastmap, '\1', sizeof (char) * SBC_MAX); | ||
409 | if (type == END_OF_RE) | ||
410 | bufp->can_be_null = 1; | ||
411 | return; | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | |||
416 | /* Entry point for POSIX code. */ | ||
417 | /* regcomp takes a regular expression as a string and compiles it. | ||
418 | |||
419 | PREG is a regex_t *. We do not expect any fields to be initialized, | ||
420 | since POSIX says we shouldn't. Thus, we set | ||
421 | |||
422 | `buffer' to the compiled pattern; | ||
423 | `used' to the length of the compiled pattern; | ||
424 | `syntax' to RE_SYNTAX_POSIX_EXTENDED if the | ||
425 | REG_EXTENDED bit in CFLAGS is set; otherwise, to | ||
426 | RE_SYNTAX_POSIX_BASIC; | ||
427 | `newline_anchor' to REG_NEWLINE being set in CFLAGS; | ||
428 | `fastmap' to an allocated space for the fastmap; | ||
429 | `fastmap_accurate' to zero; | ||
430 | `re_nsub' to the number of subexpressions in PATTERN. | ||
431 | |||
432 | PATTERN is the address of the pattern string. | ||
433 | |||
434 | CFLAGS is a series of bits which affect compilation. | ||
435 | |||
436 | If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we | ||
437 | use POSIX basic syntax. | ||
438 | |||
439 | If REG_NEWLINE is set, then . and [^...] don't match newline. | ||
440 | Also, regexec will try a match beginning after every newline. | ||
441 | |||
442 | If REG_ICASE is set, then we considers upper- and lowercase | ||
443 | versions of letters to be equivalent when matching. | ||
444 | |||
445 | If REG_NOSUB is set, then when PREG is passed to regexec, that | ||
446 | routine will report only success or failure, and nothing about the | ||
447 | registers. | ||
448 | |||
449 | It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for | ||
450 | the return codes and their meanings.) */ | ||
451 | |||
452 | int | ||
453 | regcomp (preg, pattern, cflags) | ||
454 | regex_t *__restrict preg; | ||
455 | const char *__restrict pattern; | ||
456 | int cflags; | ||
457 | { | ||
458 | reg_errcode_t ret; | ||
459 | reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED | ||
460 | : RE_SYNTAX_POSIX_BASIC); | ||
461 | |||
462 | preg->buffer = NULL; | ||
463 | preg->allocated = 0; | ||
464 | preg->used = 0; | ||
465 | |||
466 | /* Try to allocate space for the fastmap. */ | ||
467 | preg->fastmap = re_malloc (char, SBC_MAX); | ||
468 | if (BE (preg->fastmap == NULL, 0)) | ||
469 | return REG_ESPACE; | ||
470 | |||
471 | syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0; | ||
472 | |||
473 | /* If REG_NEWLINE is set, newlines are treated differently. */ | ||
474 | if (cflags & REG_NEWLINE) | ||
475 | { /* REG_NEWLINE implies neither . nor [^...] match newline. */ | ||
476 | syntax &= ~RE_DOT_NEWLINE; | ||
477 | syntax |= RE_HAT_LISTS_NOT_NEWLINE; | ||
478 | /* It also changes the matching behavior. */ | ||
479 | preg->newline_anchor = 1; | ||
480 | } | ||
481 | else | ||
482 | preg->newline_anchor = 0; | ||
483 | preg->no_sub = !!(cflags & REG_NOSUB); | ||
484 | preg->translate = NULL; | ||
485 | |||
486 | ret = re_compile_internal (preg, pattern, strlen (pattern), syntax); | ||
487 | |||
488 | /* POSIX doesn't distinguish between an unmatched open-group and an | ||
489 | unmatched close-group: both are REG_EPAREN. */ | ||
490 | if (ret == REG_ERPAREN) | ||
491 | ret = REG_EPAREN; | ||
492 | |||
493 | /* We have already checked preg->fastmap != NULL. */ | ||
494 | if (BE (ret == REG_NOERROR, 1)) | ||
495 | /* Compute the fastmap now, since regexec cannot modify the pattern | ||
496 | buffer. This function never fails in this implementation. */ | ||
497 | (void) re_compile_fastmap (preg); | ||
498 | else | ||
499 | { | ||
500 | /* Some error occurred while compiling the expression. */ | ||
501 | re_free (preg->fastmap); | ||
502 | preg->fastmap = NULL; | ||
503 | } | ||
504 | |||
505 | return (int) ret; | ||
506 | } | ||
507 | #ifdef _LIBC | ||
508 | weak_alias (__regcomp, regcomp) | ||
509 | #endif | ||
510 | |||
511 | /* Returns a message corresponding to an error code, ERRCODE, returned | ||
512 | from either regcomp or regexec. We don't use PREG here. */ | ||
513 | |||
514 | #ifdef _LIBC | ||
515 | size_t | ||
516 | regerror (errcode, preg, errbuf, errbuf_size) | ||
517 | int errcode; | ||
518 | const regex_t *__restrict preg; | ||
519 | char *__restrict errbuf; | ||
520 | size_t errbuf_size; | ||
521 | #else /* size_t might promote */ | ||
522 | size_t | ||
523 | regerror (int errcode, const regex_t *__restrict preg, | ||
524 | char *__restrict errbuf, size_t errbuf_size) | ||
525 | #endif | ||
526 | { | ||
527 | const char *msg; | ||
528 | size_t msg_size; | ||
529 | |||
530 | if (BE (errcode < 0 | ||
531 | || errcode >= (int) (sizeof (__re_error_msgid_idx) | ||
532 | / sizeof (__re_error_msgid_idx[0])), 0)) | ||
533 | /* Only error codes returned by the rest of the code should be passed | ||
534 | to this routine. If we are given anything else, or if other regex | ||
535 | code generates an invalid error code, then the program has a bug. | ||
536 | Dump core so we can fix it. */ | ||
537 | abort (); | ||
538 | |||
539 | msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); | ||
540 | |||
541 | msg_size = strlen (msg) + 1; /* Includes the null. */ | ||
542 | |||
543 | if (BE (errbuf_size != 0, 1)) | ||
544 | { | ||
545 | if (BE (msg_size > errbuf_size, 0)) | ||
546 | { | ||
547 | #if defined HAVE_MEMPCPY || defined _LIBC | ||
548 | *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; | ||
549 | #else | ||
550 | memcpy (errbuf, msg, errbuf_size - 1); | ||
551 | errbuf[errbuf_size - 1] = 0; | ||
552 | #endif | ||
553 | } | ||
554 | else | ||
555 | memcpy (errbuf, msg, msg_size); | ||
556 | } | ||
557 | |||
558 | return msg_size; | ||
559 | } | ||
560 | #ifdef _LIBC | ||
561 | weak_alias (__regerror, regerror) | ||
562 | #endif | ||
563 | |||
564 | |||
565 | #ifdef RE_ENABLE_I18N | ||
566 | /* This static array is used for the map to single-byte characters when | ||
567 | UTF-8 is used. Otherwise we would allocate memory just to initialize | ||
568 | it the same all the time. UTF-8 is the preferred encoding so this is | ||
569 | a worthwhile optimization. */ | ||
570 | static const bitset_t utf8_sb_map = | ||
571 | { | ||
572 | /* Set the first 128 bits. */ | ||
573 | # if 4 * BITSET_WORD_BITS < ASCII_CHARS | ||
574 | # error "bitset_word_t is narrower than 32 bits" | ||
575 | # elif 3 * BITSET_WORD_BITS < ASCII_CHARS | ||
576 | BITSET_WORD_MAX, BITSET_WORD_MAX, BITSET_WORD_MAX, | ||
577 | # elif 2 * BITSET_WORD_BITS < ASCII_CHARS | ||
578 | BITSET_WORD_MAX, BITSET_WORD_MAX, | ||
579 | # elif 1 * BITSET_WORD_BITS < ASCII_CHARS | ||
580 | BITSET_WORD_MAX, | ||
581 | # endif | ||
582 | (BITSET_WORD_MAX | ||
583 | >> (SBC_MAX % BITSET_WORD_BITS == 0 | ||
584 | ? 0 | ||
585 | : BITSET_WORD_BITS - SBC_MAX % BITSET_WORD_BITS)) | ||
586 | }; | ||
587 | #endif | ||
588 | |||
589 | |||
590 | static void | ||
591 | free_dfa_content (re_dfa_t *dfa) | ||
592 | { | ||
593 | Idx i, j; | ||
594 | |||
595 | if (dfa->nodes) | ||
596 | for (i = 0; i < dfa->nodes_len; ++i) | ||
597 | free_token (dfa->nodes + i); | ||
598 | re_free (dfa->nexts); | ||
599 | for (i = 0; i < dfa->nodes_len; ++i) | ||
600 | { | ||
601 | if (dfa->eclosures != NULL) | ||
602 | re_node_set_free (dfa->eclosures + i); | ||
603 | if (dfa->inveclosures != NULL) | ||
604 | re_node_set_free (dfa->inveclosures + i); | ||
605 | if (dfa->edests != NULL) | ||
606 | re_node_set_free (dfa->edests + i); | ||
607 | } | ||
608 | re_free (dfa->edests); | ||
609 | re_free (dfa->eclosures); | ||
610 | re_free (dfa->inveclosures); | ||
611 | re_free (dfa->nodes); | ||
612 | |||
613 | if (dfa->state_table) | ||
614 | for (i = 0; i <= dfa->state_hash_mask; ++i) | ||
615 | { | ||
616 | struct re_state_table_entry *entry = dfa->state_table + i; | ||
617 | for (j = 0; j < entry->num; ++j) | ||
618 | { | ||
619 | re_dfastate_t *state = entry->array[j]; | ||
620 | free_state (state); | ||
621 | } | ||
622 | re_free (entry->array); | ||
623 | } | ||
624 | re_free (dfa->state_table); | ||
625 | #ifdef RE_ENABLE_I18N | ||
626 | if (dfa->sb_char != utf8_sb_map) | ||
627 | re_free (dfa->sb_char); | ||
628 | #endif | ||
629 | re_free (dfa->subexp_map); | ||
630 | #ifdef DEBUG | ||
631 | re_free (dfa->re_str); | ||
632 | #endif | ||
633 | |||
634 | re_free (dfa); | ||
635 | } | ||
636 | |||
637 | |||
638 | /* Free dynamically allocated space used by PREG. */ | ||
639 | |||
640 | void | ||
641 | regfree (preg) | ||
642 | regex_t *preg; | ||
643 | { | ||
644 | re_dfa_t *dfa = (re_dfa_t *) preg->buffer; | ||
645 | if (BE (dfa != NULL, 1)) | ||
646 | free_dfa_content (dfa); | ||
647 | preg->buffer = NULL; | ||
648 | preg->allocated = 0; | ||
649 | |||
650 | re_free (preg->fastmap); | ||
651 | preg->fastmap = NULL; | ||
652 | |||
653 | re_free (preg->translate); | ||
654 | preg->translate = NULL; | ||
655 | } | ||
656 | #ifdef _LIBC | ||
657 | weak_alias (__regfree, regfree) | ||
658 | #endif | ||
659 | |||
660 | /* Entry points compatible with 4.2 BSD regex library. We don't define | ||
661 | them unless specifically requested. */ | ||
662 | |||
663 | #if defined _REGEX_RE_COMP || defined _LIBC | ||
664 | |||
665 | /* BSD has one and only one pattern buffer. */ | ||
666 | static struct re_pattern_buffer re_comp_buf; | ||
667 | |||
668 | char * | ||
669 | # ifdef _LIBC | ||
670 | /* Make these definitions weak in libc, so POSIX programs can redefine | ||
671 | these names if they don't use our functions, and still use | ||
672 | regcomp/regexec above without link errors. */ | ||
673 | weak_function | ||
674 | # endif | ||
675 | re_comp (s) | ||
676 | const char *s; | ||
677 | { | ||
678 | reg_errcode_t ret; | ||
679 | char *fastmap; | ||
680 | |||
681 | if (!s) | ||
682 | { | ||
683 | if (!re_comp_buf.buffer) | ||
684 | return gettext ("No previous regular expression"); | ||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | if (re_comp_buf.buffer) | ||
689 | { | ||
690 | fastmap = re_comp_buf.fastmap; | ||
691 | re_comp_buf.fastmap = NULL; | ||
692 | __regfree (&re_comp_buf); | ||
693 | memset (&re_comp_buf, '\0', sizeof (re_comp_buf)); | ||
694 | re_comp_buf.fastmap = fastmap; | ||
695 | } | ||
696 | |||
697 | if (re_comp_buf.fastmap == NULL) | ||
698 | { | ||
699 | re_comp_buf.fastmap = (char *) malloc (SBC_MAX); | ||
700 | if (re_comp_buf.fastmap == NULL) | ||
701 | return (char *) gettext (__re_error_msgid | ||
702 | + __re_error_msgid_idx[(int) REG_ESPACE]); | ||
703 | } | ||
704 | |||
705 | /* Since `re_exec' always passes NULL for the `regs' argument, we | ||
706 | don't need to initialize the pattern buffer fields which affect it. */ | ||
707 | |||
708 | /* Match anchors at newlines. */ | ||
709 | re_comp_buf.newline_anchor = 1; | ||
710 | |||
711 | ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options); | ||
712 | |||
713 | if (!ret) | ||
714 | return NULL; | ||
715 | |||
716 | /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ | ||
717 | return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); | ||
718 | } | ||
719 | |||
720 | #ifdef _LIBC | ||
721 | libc_freeres_fn (free_mem) | ||
722 | { | ||
723 | __regfree (&re_comp_buf); | ||
724 | } | ||
725 | #endif | ||
726 | |||
727 | #endif /* _REGEX_RE_COMP */ | ||
728 | |||
729 | /* Internal entry point. | ||
730 | Compile the regular expression PATTERN, whose length is LENGTH. | ||
731 | SYNTAX indicate regular expression's syntax. */ | ||
732 | |||
733 | static reg_errcode_t | ||
734 | re_compile_internal (regex_t *preg, const char * pattern, size_t length, | ||
735 | reg_syntax_t syntax) | ||
736 | { | ||
737 | reg_errcode_t err = REG_NOERROR; | ||
738 | re_dfa_t *dfa; | ||
739 | re_string_t regexp; | ||
740 | |||
741 | /* Initialize the pattern buffer. */ | ||
742 | preg->fastmap_accurate = 0; | ||
743 | preg->syntax = syntax; | ||
744 | preg->not_bol = preg->not_eol = 0; | ||
745 | preg->used = 0; | ||
746 | preg->re_nsub = 0; | ||
747 | preg->can_be_null = 0; | ||
748 | preg->regs_allocated = REGS_UNALLOCATED; | ||
749 | |||
750 | /* Initialize the dfa. */ | ||
751 | dfa = (re_dfa_t *) preg->buffer; | ||
752 | if (BE (preg->allocated < sizeof (re_dfa_t), 0)) | ||
753 | { | ||
754 | /* If zero allocated, but buffer is non-null, try to realloc | ||
755 | enough space. This loses if buffer's address is bogus, but | ||
756 | that is the user's responsibility. If ->buffer is NULL this | ||
757 | is a simple allocation. */ | ||
758 | dfa = re_realloc (preg->buffer, re_dfa_t, 1); | ||
759 | if (dfa == NULL) | ||
760 | return REG_ESPACE; | ||
761 | preg->allocated = sizeof (re_dfa_t); | ||
762 | preg->buffer = (unsigned char *) dfa; | ||
763 | } | ||
764 | preg->used = sizeof (re_dfa_t); | ||
765 | |||
766 | err = init_dfa (dfa, length); | ||
767 | if (BE (err != REG_NOERROR, 0)) | ||
768 | { | ||
769 | free_dfa_content (dfa); | ||
770 | preg->buffer = NULL; | ||
771 | preg->allocated = 0; | ||
772 | return err; | ||
773 | } | ||
774 | #ifdef DEBUG | ||
775 | /* Note: length+1 will not overflow since it is checked in init_dfa. */ | ||
776 | dfa->re_str = re_malloc (char, length + 1); | ||
777 | strncpy (dfa->re_str, pattern, length + 1); | ||
778 | #endif | ||
779 | |||
780 | __libc_lock_init (dfa->lock); | ||
781 | |||
782 | err = re_string_construct (®exp, pattern, length, preg->translate, | ||
783 | syntax & RE_ICASE, dfa); | ||
784 | if (BE (err != REG_NOERROR, 0)) | ||
785 | { | ||
786 | re_compile_internal_free_return: | ||
787 | free_workarea_compile (preg); | ||
788 | re_string_destruct (®exp); | ||
789 | free_dfa_content (dfa); | ||
790 | preg->buffer = NULL; | ||
791 | preg->allocated = 0; | ||
792 | return err; | ||
793 | } | ||
794 | |||
795 | /* Parse the regular expression, and build a structure tree. */ | ||
796 | preg->re_nsub = 0; | ||
797 | dfa->str_tree = parse (®exp, preg, syntax, &err); | ||
798 | if (BE (dfa->str_tree == NULL, 0)) | ||
799 | goto re_compile_internal_free_return; | ||
800 | |||
801 | /* Analyze the tree and create the nfa. */ | ||
802 | err = analyze (preg); | ||
803 | if (BE (err != REG_NOERROR, 0)) | ||
804 | goto re_compile_internal_free_return; | ||
805 | |||
806 | #ifdef RE_ENABLE_I18N | ||
807 | /* If possible, do searching in single byte encoding to speed things up. */ | ||
808 | if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL) | ||
809 | optimize_utf8 (dfa); | ||
810 | #endif | ||
811 | |||
812 | /* Then create the initial state of the dfa. */ | ||
813 | err = create_initial_state (dfa); | ||
814 | |||
815 | /* Release work areas. */ | ||
816 | free_workarea_compile (preg); | ||
817 | re_string_destruct (®exp); | ||
818 | |||
819 | if (BE (err != REG_NOERROR, 0)) | ||
820 | { | ||
821 | free_dfa_content (dfa); | ||
822 | preg->buffer = NULL; | ||
823 | preg->allocated = 0; | ||
824 | } | ||
825 | |||
826 | return err; | ||
827 | } | ||
828 | |||
829 | /* Initialize DFA. We use the length of the regular expression PAT_LEN | ||
830 | as the initial length of some arrays. */ | ||
831 | |||
832 | static reg_errcode_t | ||
833 | init_dfa (re_dfa_t *dfa, size_t pat_len) | ||
834 | { | ||
835 | __re_size_t table_size; | ||
836 | #ifndef _LIBC | ||
837 | char *codeset_name; | ||
838 | #endif | ||
839 | #ifdef RE_ENABLE_I18N | ||
840 | size_t max_i18n_object_size = MAX (sizeof (wchar_t), sizeof (wctype_t)); | ||
841 | #else | ||
842 | size_t max_i18n_object_size = 0; | ||
843 | #endif | ||
844 | size_t max_object_size = | ||
845 | MAX (sizeof (struct re_state_table_entry), | ||
846 | MAX (sizeof (re_token_t), | ||
847 | MAX (sizeof (re_node_set), | ||
848 | MAX (sizeof (regmatch_t), | ||
849 | max_i18n_object_size)))); | ||
850 | |||
851 | memset (dfa, '\0', sizeof (re_dfa_t)); | ||
852 | |||
853 | /* Force allocation of str_tree_storage the first time. */ | ||
854 | dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; | ||
855 | |||
856 | /* Avoid overflows. The extra "/ 2" is for the table_size doubling | ||
857 | calculation below, and for similar doubling calculations | ||
858 | elsewhere. And it's <= rather than <, because some of the | ||
859 | doubling calculations add 1 afterwards. */ | ||
860 | if (BE (SIZE_MAX / max_object_size / 2 <= pat_len, 0)) | ||
861 | return REG_ESPACE; | ||
862 | |||
863 | dfa->nodes_alloc = pat_len + 1; | ||
864 | dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc); | ||
865 | |||
866 | /* table_size = 2 ^ ceil(log pat_len) */ | ||
867 | for (table_size = 1; ; table_size <<= 1) | ||
868 | if (table_size > pat_len) | ||
869 | break; | ||
870 | |||
871 | dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size); | ||
872 | dfa->state_hash_mask = table_size - 1; | ||
873 | |||
874 | dfa->mb_cur_max = MB_CUR_MAX; | ||
875 | #ifdef _LIBC | ||
876 | if (dfa->mb_cur_max == 6 | ||
877 | && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0) | ||
878 | dfa->is_utf8 = 1; | ||
879 | dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII) | ||
880 | != 0); | ||
881 | #else | ||
882 | # ifdef HAVE_LANGINFO_CODESET | ||
883 | codeset_name = nl_langinfo (CODESET); | ||
884 | # else | ||
885 | codeset_name = getenv ("LC_ALL"); | ||
886 | if (codeset_name == NULL || codeset_name[0] == '\0') | ||
887 | codeset_name = getenv ("LC_CTYPE"); | ||
888 | if (codeset_name == NULL || codeset_name[0] == '\0') | ||
889 | codeset_name = getenv ("LANG"); | ||
890 | if (codeset_name == NULL) | ||
891 | codeset_name = ""; | ||
892 | else if (strchr (codeset_name, '.') != NULL) | ||
893 | codeset_name = strchr (codeset_name, '.') + 1; | ||
894 | # endif | ||
895 | |||
896 | if (strcasecmp (codeset_name, "UTF-8") == 0 | ||
897 | || strcasecmp (codeset_name, "UTF8") == 0) | ||
898 | dfa->is_utf8 = 1; | ||
899 | |||
900 | /* We check exhaustively in the loop below if this charset is a | ||
901 | superset of ASCII. */ | ||
902 | dfa->map_notascii = 0; | ||
903 | #endif | ||
904 | |||
905 | #ifdef RE_ENABLE_I18N | ||
906 | if (dfa->mb_cur_max > 1) | ||
907 | { | ||
908 | if (dfa->is_utf8) | ||
909 | dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map; | ||
910 | else | ||
911 | { | ||
912 | int i, j, ch; | ||
913 | |||
914 | dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); | ||
915 | if (BE (dfa->sb_char == NULL, 0)) | ||
916 | return REG_ESPACE; | ||
917 | |||
918 | /* Set the bits corresponding to single byte chars. */ | ||
919 | for (i = 0, ch = 0; i < BITSET_WORDS; ++i) | ||
920 | for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) | ||
921 | { | ||
922 | wint_t wch = __btowc (ch); | ||
923 | if (wch != WEOF) | ||
924 | dfa->sb_char[i] |= (bitset_word_t) 1 << j; | ||
925 | # ifndef _LIBC | ||
926 | if (isascii (ch) && wch != ch) | ||
927 | dfa->map_notascii = 1; | ||
928 | # endif | ||
929 | } | ||
930 | } | ||
931 | } | ||
932 | #endif | ||
933 | |||
934 | if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0)) | ||
935 | return REG_ESPACE; | ||
936 | return REG_NOERROR; | ||
937 | } | ||
938 | |||
939 | /* Initialize WORD_CHAR table, which indicate which character is | ||
940 | "word". In this case "word" means that it is the word construction | ||
941 | character used by some operators like "\<", "\>", etc. */ | ||
942 | |||
943 | static void | ||
944 | internal_function | ||
945 | init_word_char (re_dfa_t *dfa) | ||
946 | { | ||
947 | int i, j, ch; | ||
948 | dfa->word_ops_used = 1; | ||
949 | for (i = 0, ch = 0; i < BITSET_WORDS; ++i) | ||
950 | for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) | ||
951 | if (isalnum (ch) || ch == '_') | ||
952 | dfa->word_char[i] |= (bitset_word_t) 1 << j; | ||
953 | } | ||
954 | |||
955 | /* Free the work area which are only used while compiling. */ | ||
956 | |||
957 | static void | ||
958 | free_workarea_compile (regex_t *preg) | ||
959 | { | ||
960 | re_dfa_t *dfa = (re_dfa_t *) preg->buffer; | ||
961 | bin_tree_storage_t *storage, *next; | ||
962 | for (storage = dfa->str_tree_storage; storage; storage = next) | ||
963 | { | ||
964 | next = storage->next; | ||
965 | re_free (storage); | ||
966 | } | ||
967 | dfa->str_tree_storage = NULL; | ||
968 | dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; | ||
969 | dfa->str_tree = NULL; | ||
970 | re_free (dfa->org_indices); | ||
971 | dfa->org_indices = NULL; | ||
972 | } | ||
973 | |||
974 | /* Create initial states for all contexts. */ | ||
975 | |||
976 | static reg_errcode_t | ||
977 | create_initial_state (re_dfa_t *dfa) | ||
978 | { | ||
979 | Idx first, i; | ||
980 | reg_errcode_t err; | ||
981 | re_node_set init_nodes; | ||
982 | |||
983 | /* Initial states have the epsilon closure of the node which is | ||
984 | the first node of the regular expression. */ | ||
985 | first = dfa->str_tree->first->node_idx; | ||
986 | dfa->init_node = first; | ||
987 | err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first); | ||
988 | if (BE (err != REG_NOERROR, 0)) | ||
989 | return err; | ||
990 | |||
991 | /* The back-references which are in initial states can epsilon transit, | ||
992 | since in this case all of the subexpressions can be null. | ||
993 | Then we add epsilon closures of the nodes which are the next nodes of | ||
994 | the back-references. */ | ||
995 | if (dfa->nbackref > 0) | ||
996 | for (i = 0; i < init_nodes.nelem; ++i) | ||
997 | { | ||
998 | Idx node_idx = init_nodes.elems[i]; | ||
999 | re_token_type_t type = dfa->nodes[node_idx].type; | ||
1000 | |||
1001 | Idx clexp_idx; | ||
1002 | if (type != OP_BACK_REF) | ||
1003 | continue; | ||
1004 | for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx) | ||
1005 | { | ||
1006 | re_token_t *clexp_node; | ||
1007 | clexp_node = dfa->nodes + init_nodes.elems[clexp_idx]; | ||
1008 | if (clexp_node->type == OP_CLOSE_SUBEXP | ||
1009 | && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx) | ||
1010 | break; | ||
1011 | } | ||
1012 | if (clexp_idx == init_nodes.nelem) | ||
1013 | continue; | ||
1014 | |||
1015 | if (type == OP_BACK_REF) | ||
1016 | { | ||
1017 | Idx dest_idx = dfa->edests[node_idx].elems[0]; | ||
1018 | if (!re_node_set_contains (&init_nodes, dest_idx)) | ||
1019 | { | ||
1020 | re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx); | ||
1021 | i = 0; | ||
1022 | } | ||
1023 | } | ||
1024 | } | ||
1025 | |||
1026 | /* It must be the first time to invoke acquire_state. */ | ||
1027 | dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0); | ||
1028 | /* We don't check ERR here, since the initial state must not be NULL. */ | ||
1029 | if (BE (dfa->init_state == NULL, 0)) | ||
1030 | return err; | ||
1031 | if (dfa->init_state->has_constraint) | ||
1032 | { | ||
1033 | dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes, | ||
1034 | CONTEXT_WORD); | ||
1035 | dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes, | ||
1036 | CONTEXT_NEWLINE); | ||
1037 | dfa->init_state_begbuf = re_acquire_state_context (&err, dfa, | ||
1038 | &init_nodes, | ||
1039 | CONTEXT_NEWLINE | ||
1040 | | CONTEXT_BEGBUF); | ||
1041 | if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL | ||
1042 | || dfa->init_state_begbuf == NULL, 0)) | ||
1043 | return err; | ||
1044 | } | ||
1045 | else | ||
1046 | dfa->init_state_word = dfa->init_state_nl | ||
1047 | = dfa->init_state_begbuf = dfa->init_state; | ||
1048 | |||
1049 | re_node_set_free (&init_nodes); | ||
1050 | return REG_NOERROR; | ||
1051 | } | ||
1052 | |||
1053 | #ifdef RE_ENABLE_I18N | ||
1054 | /* If it is possible to do searching in single byte encoding instead of UTF-8 | ||
1055 | to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change | ||
1056 | DFA nodes where needed. */ | ||
1057 | |||
1058 | static void | ||
1059 | optimize_utf8 (re_dfa_t *dfa) | ||
1060 | { | ||
1061 | Idx node; | ||
1062 | int i; | ||
1063 | bool mb_chars = false; | ||
1064 | bool has_period = false; | ||
1065 | |||
1066 | for (node = 0; node < dfa->nodes_len; ++node) | ||
1067 | switch (dfa->nodes[node].type) | ||
1068 | { | ||
1069 | case CHARACTER: | ||
1070 | if (dfa->nodes[node].opr.c >= ASCII_CHARS) | ||
1071 | mb_chars = true; | ||
1072 | break; | ||
1073 | case ANCHOR: | ||
1074 | switch (dfa->nodes[node].opr.idx) | ||
1075 | { | ||
1076 | case LINE_FIRST: | ||
1077 | case LINE_LAST: | ||
1078 | case BUF_FIRST: | ||
1079 | case BUF_LAST: | ||
1080 | break; | ||
1081 | default: | ||
1082 | /* Word anchors etc. cannot be handled. */ | ||
1083 | return; | ||
1084 | } | ||
1085 | break; | ||
1086 | case OP_PERIOD: | ||
1087 | has_period = true; | ||
1088 | break; | ||
1089 | case OP_BACK_REF: | ||
1090 | case OP_ALT: | ||
1091 | case END_OF_RE: | ||
1092 | case OP_DUP_ASTERISK: | ||
1093 | case OP_OPEN_SUBEXP: | ||
1094 | case OP_CLOSE_SUBEXP: | ||
1095 | break; | ||
1096 | case COMPLEX_BRACKET: | ||
1097 | return; | ||
1098 | case SIMPLE_BRACKET: | ||
1099 | /* Just double check. */ | ||
1100 | { | ||
1101 | int rshift = (ASCII_CHARS % BITSET_WORD_BITS == 0 | ||
1102 | ? 0 | ||
1103 | : BITSET_WORD_BITS - ASCII_CHARS % BITSET_WORD_BITS); | ||
1104 | for (i = ASCII_CHARS / BITSET_WORD_BITS; i < BITSET_WORDS; ++i) | ||
1105 | { | ||
1106 | if (dfa->nodes[node].opr.sbcset[i] >> rshift != 0) | ||
1107 | return; | ||
1108 | rshift = 0; | ||
1109 | } | ||
1110 | } | ||
1111 | break; | ||
1112 | default: | ||
1113 | abort (); | ||
1114 | } | ||
1115 | |||
1116 | if (mb_chars || has_period) | ||
1117 | for (node = 0; node < dfa->nodes_len; ++node) | ||
1118 | { | ||
1119 | if (dfa->nodes[node].type == CHARACTER | ||
1120 | && dfa->nodes[node].opr.c >= ASCII_CHARS) | ||
1121 | dfa->nodes[node].mb_partial = 0; | ||
1122 | else if (dfa->nodes[node].type == OP_PERIOD) | ||
1123 | dfa->nodes[node].type = OP_UTF8_PERIOD; | ||
1124 | } | ||
1125 | |||
1126 | /* The search can be in single byte locale. */ | ||
1127 | dfa->mb_cur_max = 1; | ||
1128 | dfa->is_utf8 = 0; | ||
1129 | dfa->has_mb_node = dfa->nbackref > 0 || has_period; | ||
1130 | } | ||
1131 | #endif | ||
1132 | |||
1133 | /* Analyze the structure tree, and calculate "first", "next", "edest", | ||
1134 | "eclosure", and "inveclosure". */ | ||
1135 | |||
1136 | static reg_errcode_t | ||
1137 | analyze (regex_t *preg) | ||
1138 | { | ||
1139 | re_dfa_t *dfa = (re_dfa_t *) preg->buffer; | ||
1140 | reg_errcode_t ret; | ||
1141 | |||
1142 | /* Allocate arrays. */ | ||
1143 | dfa->nexts = re_malloc (Idx, dfa->nodes_alloc); | ||
1144 | dfa->org_indices = re_malloc (Idx, dfa->nodes_alloc); | ||
1145 | dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc); | ||
1146 | dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc); | ||
1147 | if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL | ||
1148 | || dfa->eclosures == NULL, 0)) | ||
1149 | return REG_ESPACE; | ||
1150 | |||
1151 | dfa->subexp_map = re_malloc (Idx, preg->re_nsub); | ||
1152 | if (dfa->subexp_map != NULL) | ||
1153 | { | ||
1154 | Idx i; | ||
1155 | for (i = 0; i < preg->re_nsub; i++) | ||
1156 | dfa->subexp_map[i] = i; | ||
1157 | preorder (dfa->str_tree, optimize_subexps, dfa); | ||
1158 | for (i = 0; i < preg->re_nsub; i++) | ||
1159 | if (dfa->subexp_map[i] != i) | ||
1160 | break; | ||
1161 | if (i == preg->re_nsub) | ||
1162 | { | ||
1163 | free (dfa->subexp_map); | ||
1164 | dfa->subexp_map = NULL; | ||
1165 | } | ||
1166 | } | ||
1167 | |||
1168 | ret = postorder (dfa->str_tree, lower_subexps, preg); | ||
1169 | if (BE (ret != REG_NOERROR, 0)) | ||
1170 | return ret; | ||
1171 | ret = postorder (dfa->str_tree, calc_first, dfa); | ||
1172 | if (BE (ret != REG_NOERROR, 0)) | ||
1173 | return ret; | ||
1174 | preorder (dfa->str_tree, calc_next, dfa); | ||
1175 | ret = preorder (dfa->str_tree, link_nfa_nodes, dfa); | ||
1176 | if (BE (ret != REG_NOERROR, 0)) | ||
1177 | return ret; | ||
1178 | ret = calc_eclosure (dfa); | ||
1179 | if (BE (ret != REG_NOERROR, 0)) | ||
1180 | return ret; | ||
1181 | |||
1182 | /* We only need this during the prune_impossible_nodes pass in regexec.c; | ||
1183 | skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */ | ||
1184 | if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match) | ||
1185 | || dfa->nbackref) | ||
1186 | { | ||
1187 | dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len); | ||
1188 | if (BE (dfa->inveclosures == NULL, 0)) | ||
1189 | return REG_ESPACE; | ||
1190 | ret = calc_inveclosure (dfa); | ||
1191 | } | ||
1192 | |||
1193 | return ret; | ||
1194 | } | ||
1195 | |||
1196 | /* Our parse trees are very unbalanced, so we cannot use a stack to | ||
1197 | implement parse tree visits. Instead, we use parent pointers and | ||
1198 | some hairy code in these two functions. */ | ||
1199 | static reg_errcode_t | ||
1200 | postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), | ||
1201 | void *extra) | ||
1202 | { | ||
1203 | bin_tree_t *node, *prev; | ||
1204 | |||
1205 | for (node = root; ; ) | ||
1206 | { | ||
1207 | /* Descend down the tree, preferably to the left (or to the right | ||
1208 | if that's the only child). */ | ||
1209 | while (node->left || node->right) | ||
1210 | if (node->left) | ||
1211 | node = node->left; | ||
1212 | else | ||
1213 | node = node->right; | ||
1214 | |||
1215 | do | ||
1216 | { | ||
1217 | reg_errcode_t err = fn (extra, node); | ||
1218 | if (BE (err != REG_NOERROR, 0)) | ||
1219 | return err; | ||
1220 | if (node->parent == NULL) | ||
1221 | return REG_NOERROR; | ||
1222 | prev = node; | ||
1223 | node = node->parent; | ||
1224 | } | ||
1225 | /* Go up while we have a node that is reached from the right. */ | ||
1226 | while (node->right == prev || node->right == NULL); | ||
1227 | node = node->right; | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | static reg_errcode_t | ||
1232 | preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)), | ||
1233 | void *extra) | ||
1234 | { | ||
1235 | bin_tree_t *node; | ||
1236 | |||
1237 | for (node = root; ; ) | ||
1238 | { | ||
1239 | reg_errcode_t err = fn (extra, node); | ||
1240 | if (BE (err != REG_NOERROR, 0)) | ||
1241 | return err; | ||
1242 | |||
1243 | /* Go to the left node, or up and to the right. */ | ||
1244 | if (node->left) | ||
1245 | node = node->left; | ||
1246 | else | ||
1247 | { | ||
1248 | bin_tree_t *prev = NULL; | ||
1249 | while (node->right == prev || node->right == NULL) | ||
1250 | { | ||
1251 | prev = node; | ||
1252 | node = node->parent; | ||
1253 | if (!node) | ||
1254 | return REG_NOERROR; | ||
1255 | } | ||
1256 | node = node->right; | ||
1257 | } | ||
1258 | } | ||
1259 | } | ||
1260 | |||
1261 | /* Optimization pass: if a SUBEXP is entirely contained, strip it and tell | ||
1262 | re_search_internal to map the inner one's opr.idx to this one's. Adjust | ||
1263 | backreferences as well. Requires a preorder visit. */ | ||
1264 | static reg_errcode_t | ||
1265 | optimize_subexps (void *extra, bin_tree_t *node) | ||
1266 | { | ||
1267 | re_dfa_t *dfa = (re_dfa_t *) extra; | ||
1268 | |||
1269 | if (node->token.type == OP_BACK_REF && dfa->subexp_map) | ||
1270 | { | ||
1271 | int idx = node->token.opr.idx; | ||
1272 | node->token.opr.idx = dfa->subexp_map[idx]; | ||
1273 | dfa->used_bkref_map |= 1 << node->token.opr.idx; | ||
1274 | } | ||
1275 | |||
1276 | else if (node->token.type == SUBEXP | ||
1277 | && node->left && node->left->token.type == SUBEXP) | ||
1278 | { | ||
1279 | Idx other_idx = node->left->token.opr.idx; | ||
1280 | |||
1281 | node->left = node->left->left; | ||
1282 | if (node->left) | ||
1283 | node->left->parent = node; | ||
1284 | |||
1285 | dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx]; | ||
1286 | if (other_idx < BITSET_WORD_BITS) | ||
1287 | dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx); | ||
1288 | } | ||
1289 | |||
1290 | return REG_NOERROR; | ||
1291 | } | ||
1292 | |||
1293 | /* Lowering pass: Turn each SUBEXP node into the appropriate concatenation | ||
1294 | of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */ | ||
1295 | static reg_errcode_t | ||
1296 | lower_subexps (void *extra, bin_tree_t *node) | ||
1297 | { | ||
1298 | regex_t *preg = (regex_t *) extra; | ||
1299 | reg_errcode_t err = REG_NOERROR; | ||
1300 | |||
1301 | if (node->left && node->left->token.type == SUBEXP) | ||
1302 | { | ||
1303 | node->left = lower_subexp (&err, preg, node->left); | ||
1304 | if (node->left) | ||
1305 | node->left->parent = node; | ||
1306 | } | ||
1307 | if (node->right && node->right->token.type == SUBEXP) | ||
1308 | { | ||
1309 | node->right = lower_subexp (&err, preg, node->right); | ||
1310 | if (node->right) | ||
1311 | node->right->parent = node; | ||
1312 | } | ||
1313 | |||
1314 | return err; | ||
1315 | } | ||
1316 | |||
1317 | static bin_tree_t * | ||
1318 | lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node) | ||
1319 | { | ||
1320 | re_dfa_t *dfa = (re_dfa_t *) preg->buffer; | ||
1321 | bin_tree_t *body = node->left; | ||
1322 | bin_tree_t *op, *cls, *tree1, *tree; | ||
1323 | |||
1324 | if (preg->no_sub | ||
1325 | /* We do not optimize empty subexpressions, because otherwise we may | ||
1326 | have bad CONCAT nodes with NULL children. This is obviously not | ||
1327 | very common, so we do not lose much. An example that triggers | ||
1328 | this case is the sed "script" /\(\)/x. */ | ||
1329 | && node->left != NULL | ||
1330 | && (node->token.opr.idx >= BITSET_WORD_BITS | ||
1331 | || !(dfa->used_bkref_map | ||
1332 | & ((bitset_word_t) 1 << node->token.opr.idx)))) | ||
1333 | return node->left; | ||
1334 | |||
1335 | /* Convert the SUBEXP node to the concatenation of an | ||
1336 | OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */ | ||
1337 | op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP); | ||
1338 | cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP); | ||
1339 | tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls; | ||
1340 | tree = create_tree (dfa, op, tree1, CONCAT); | ||
1341 | if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0)) | ||
1342 | { | ||
1343 | *err = REG_ESPACE; | ||
1344 | return NULL; | ||
1345 | } | ||
1346 | |||
1347 | op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx; | ||
1348 | op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp; | ||
1349 | return tree; | ||
1350 | } | ||
1351 | |||
1352 | /* Pass 1 in building the NFA: compute FIRST and create unlinked automaton | ||
1353 | nodes. Requires a postorder visit. */ | ||
1354 | static reg_errcode_t | ||
1355 | calc_first (void *extra, bin_tree_t *node) | ||
1356 | { | ||
1357 | re_dfa_t *dfa = (re_dfa_t *) extra; | ||
1358 | if (node->token.type == CONCAT) | ||
1359 | { | ||
1360 | node->first = node->left->first; | ||
1361 | node->node_idx = node->left->node_idx; | ||
1362 | } | ||
1363 | else | ||
1364 | { | ||
1365 | node->first = node; | ||
1366 | node->node_idx = re_dfa_add_node (dfa, node->token); | ||
1367 | if (BE (node->node_idx == REG_MISSING, 0)) | ||
1368 | return REG_ESPACE; | ||
1369 | } | ||
1370 | return REG_NOERROR; | ||
1371 | } | ||
1372 | |||
1373 | /* Pass 2: compute NEXT on the tree. Preorder visit. */ | ||
1374 | static reg_errcode_t | ||
1375 | calc_next (void *extra, bin_tree_t *node) | ||
1376 | { | ||
1377 | switch (node->token.type) | ||
1378 | { | ||
1379 | case OP_DUP_ASTERISK: | ||
1380 | node->left->next = node; | ||
1381 | break; | ||
1382 | case CONCAT: | ||
1383 | node->left->next = node->right->first; | ||
1384 | node->right->next = node->next; | ||
1385 | break; | ||
1386 | default: | ||
1387 | if (node->left) | ||
1388 | node->left->next = node->next; | ||
1389 | if (node->right) | ||
1390 | node->right->next = node->next; | ||
1391 | break; | ||
1392 | } | ||
1393 | return REG_NOERROR; | ||
1394 | } | ||
1395 | |||
1396 | /* Pass 3: link all DFA nodes to their NEXT node (any order will do). */ | ||
1397 | static reg_errcode_t | ||
1398 | link_nfa_nodes (void *extra, bin_tree_t *node) | ||
1399 | { | ||
1400 | re_dfa_t *dfa = (re_dfa_t *) extra; | ||
1401 | Idx idx = node->node_idx; | ||
1402 | reg_errcode_t err = REG_NOERROR; | ||
1403 | |||
1404 | switch (node->token.type) | ||
1405 | { | ||
1406 | case CONCAT: | ||
1407 | break; | ||
1408 | |||
1409 | case END_OF_RE: | ||
1410 | assert (node->next == NULL); | ||
1411 | break; | ||
1412 | |||
1413 | case OP_DUP_ASTERISK: | ||
1414 | case OP_ALT: | ||
1415 | { | ||
1416 | Idx left, right; | ||
1417 | dfa->has_plural_match = 1; | ||
1418 | if (node->left != NULL) | ||
1419 | left = node->left->first->node_idx; | ||
1420 | else | ||
1421 | left = node->next->node_idx; | ||
1422 | if (node->right != NULL) | ||
1423 | right = node->right->first->node_idx; | ||
1424 | else | ||
1425 | right = node->next->node_idx; | ||
1426 | assert (REG_VALID_INDEX (left)); | ||
1427 | assert (REG_VALID_INDEX (right)); | ||
1428 | err = re_node_set_init_2 (dfa->edests + idx, left, right); | ||
1429 | } | ||
1430 | break; | ||
1431 | |||
1432 | case ANCHOR: | ||
1433 | case OP_OPEN_SUBEXP: | ||
1434 | case OP_CLOSE_SUBEXP: | ||
1435 | err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx); | ||
1436 | break; | ||
1437 | |||
1438 | case OP_BACK_REF: | ||
1439 | dfa->nexts[idx] = node->next->node_idx; | ||
1440 | if (node->token.type == OP_BACK_REF) | ||
1441 | re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]); | ||
1442 | break; | ||
1443 | |||
1444 | default: | ||
1445 | assert (!IS_EPSILON_NODE (node->token.type)); | ||
1446 | dfa->nexts[idx] = node->next->node_idx; | ||
1447 | break; | ||
1448 | } | ||
1449 | |||
1450 | return err; | ||
1451 | } | ||
1452 | |||
1453 | /* Duplicate the epsilon closure of the node ROOT_NODE. | ||
1454 | Note that duplicated nodes have constraint INIT_CONSTRAINT in addition | ||
1455 | to their own constraint. */ | ||
1456 | |||
1457 | static reg_errcode_t | ||
1458 | internal_function | ||
1459 | duplicate_node_closure (re_dfa_t *dfa, Idx top_org_node, Idx top_clone_node, | ||
1460 | Idx root_node, unsigned int init_constraint) | ||
1461 | { | ||
1462 | Idx org_node, clone_node; | ||
1463 | bool ok; | ||
1464 | unsigned int constraint = init_constraint; | ||
1465 | for (org_node = top_org_node, clone_node = top_clone_node;;) | ||
1466 | { | ||
1467 | Idx org_dest, clone_dest; | ||
1468 | if (dfa->nodes[org_node].type == OP_BACK_REF) | ||
1469 | { | ||
1470 | /* If the back reference epsilon-transit, its destination must | ||
1471 | also have the constraint. Then duplicate the epsilon closure | ||
1472 | of the destination of the back reference, and store it in | ||
1473 | edests of the back reference. */ | ||
1474 | org_dest = dfa->nexts[org_node]; | ||
1475 | re_node_set_empty (dfa->edests + clone_node); | ||
1476 | clone_dest = duplicate_node (dfa, org_dest, constraint); | ||
1477 | if (BE (clone_dest == REG_MISSING, 0)) | ||
1478 | return REG_ESPACE; | ||
1479 | dfa->nexts[clone_node] = dfa->nexts[org_node]; | ||
1480 | ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); | ||
1481 | if (BE (! ok, 0)) | ||
1482 | return REG_ESPACE; | ||
1483 | } | ||
1484 | else if (dfa->edests[org_node].nelem == 0) | ||
1485 | { | ||
1486 | /* In case of the node can't epsilon-transit, don't duplicate the | ||
1487 | destination and store the original destination as the | ||
1488 | destination of the node. */ | ||
1489 | dfa->nexts[clone_node] = dfa->nexts[org_node]; | ||
1490 | break; | ||
1491 | } | ||
1492 | else if (dfa->edests[org_node].nelem == 1) | ||
1493 | { | ||
1494 | /* In case of the node can epsilon-transit, and it has only one | ||
1495 | destination. */ | ||
1496 | org_dest = dfa->edests[org_node].elems[0]; | ||
1497 | re_node_set_empty (dfa->edests + clone_node); | ||
1498 | if (dfa->nodes[org_node].type == ANCHOR) | ||
1499 | { | ||
1500 | /* In case of the node has another constraint, append it. */ | ||
1501 | if (org_node == root_node && clone_node != org_node) | ||
1502 | { | ||
1503 | /* ...but if the node is root_node itself, it means the | ||
1504 | epsilon closure have a loop, then tie it to the | ||
1505 | destination of the root_node. */ | ||
1506 | ok = re_node_set_insert (dfa->edests + clone_node, org_dest); | ||
1507 | if (BE (! ok, 0)) | ||
1508 | return REG_ESPACE; | ||
1509 | break; | ||
1510 | } | ||
1511 | constraint |= dfa->nodes[org_node].opr.ctx_type; | ||
1512 | } | ||
1513 | clone_dest = duplicate_node (dfa, org_dest, constraint); | ||
1514 | if (BE (clone_dest == REG_MISSING, 0)) | ||
1515 | return REG_ESPACE; | ||
1516 | ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); | ||
1517 | if (BE (! ok, 0)) | ||
1518 | return REG_ESPACE; | ||
1519 | } | ||
1520 | else /* dfa->edests[org_node].nelem == 2 */ | ||
1521 | { | ||
1522 | /* In case of the node can epsilon-transit, and it has two | ||
1523 | destinations. In the bin_tree_t and DFA, that's '|' and '*'. */ | ||
1524 | org_dest = dfa->edests[org_node].elems[0]; | ||
1525 | re_node_set_empty (dfa->edests + clone_node); | ||
1526 | /* Search for a duplicated node which satisfies the constraint. */ | ||
1527 | clone_dest = search_duplicated_node (dfa, org_dest, constraint); | ||
1528 | if (clone_dest == REG_MISSING) | ||
1529 | { | ||
1530 | /* There are no such a duplicated node, create a new one. */ | ||
1531 | reg_errcode_t err; | ||
1532 | clone_dest = duplicate_node (dfa, org_dest, constraint); | ||
1533 | if (BE (clone_dest == REG_MISSING, 0)) | ||
1534 | return REG_ESPACE; | ||
1535 | ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); | ||
1536 | if (BE (! ok, 0)) | ||
1537 | return REG_ESPACE; | ||
1538 | err = duplicate_node_closure (dfa, org_dest, clone_dest, | ||
1539 | root_node, constraint); | ||
1540 | if (BE (err != REG_NOERROR, 0)) | ||
1541 | return err; | ||
1542 | } | ||
1543 | else | ||
1544 | { | ||
1545 | /* There are a duplicated node which satisfy the constraint, | ||
1546 | use it to avoid infinite loop. */ | ||
1547 | ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); | ||
1548 | if (BE (! ok, 0)) | ||
1549 | return REG_ESPACE; | ||
1550 | } | ||
1551 | |||
1552 | org_dest = dfa->edests[org_node].elems[1]; | ||
1553 | clone_dest = duplicate_node (dfa, org_dest, constraint); | ||
1554 | if (BE (clone_dest == REG_MISSING, 0)) | ||
1555 | return REG_ESPACE; | ||
1556 | ok = re_node_set_insert (dfa->edests + clone_node, clone_dest); | ||
1557 | if (BE (! ok, 0)) | ||
1558 | return REG_ESPACE; | ||
1559 | } | ||
1560 | org_node = org_dest; | ||
1561 | clone_node = clone_dest; | ||
1562 | } | ||
1563 | return REG_NOERROR; | ||
1564 | } | ||
1565 | |||
1566 | /* Search for a node which is duplicated from the node ORG_NODE, and | ||
1567 | satisfies the constraint CONSTRAINT. */ | ||
1568 | |||
1569 | static Idx | ||
1570 | search_duplicated_node (const re_dfa_t *dfa, Idx org_node, | ||
1571 | unsigned int constraint) | ||
1572 | { | ||
1573 | Idx idx; | ||
1574 | for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx) | ||
1575 | { | ||
1576 | if (org_node == dfa->org_indices[idx] | ||
1577 | && constraint == dfa->nodes[idx].constraint) | ||
1578 | return idx; /* Found. */ | ||
1579 | } | ||
1580 | return REG_MISSING; /* Not found. */ | ||
1581 | } | ||
1582 | |||
1583 | /* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT. | ||
1584 | Return the index of the new node, or REG_MISSING if insufficient storage is | ||
1585 | available. */ | ||
1586 | |||
1587 | static Idx | ||
1588 | duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int constraint) | ||
1589 | { | ||
1590 | Idx dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]); | ||
1591 | if (BE (dup_idx != REG_MISSING, 1)) | ||
1592 | { | ||
1593 | dfa->nodes[dup_idx].constraint = constraint; | ||
1594 | if (dfa->nodes[org_idx].type == ANCHOR) | ||
1595 | dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type; | ||
1596 | dfa->nodes[dup_idx].duplicated = 1; | ||
1597 | |||
1598 | /* Store the index of the original node. */ | ||
1599 | dfa->org_indices[dup_idx] = org_idx; | ||
1600 | } | ||
1601 | return dup_idx; | ||
1602 | } | ||
1603 | |||
1604 | static reg_errcode_t | ||
1605 | calc_inveclosure (re_dfa_t *dfa) | ||
1606 | { | ||
1607 | Idx src, idx; | ||
1608 | bool ok; | ||
1609 | for (idx = 0; idx < dfa->nodes_len; ++idx) | ||
1610 | re_node_set_init_empty (dfa->inveclosures + idx); | ||
1611 | |||
1612 | for (src = 0; src < dfa->nodes_len; ++src) | ||
1613 | { | ||
1614 | Idx *elems = dfa->eclosures[src].elems; | ||
1615 | for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx) | ||
1616 | { | ||
1617 | ok = re_node_set_insert_last (dfa->inveclosures + elems[idx], src); | ||
1618 | if (BE (! ok, 0)) | ||
1619 | return REG_ESPACE; | ||
1620 | } | ||
1621 | } | ||
1622 | |||
1623 | return REG_NOERROR; | ||
1624 | } | ||
1625 | |||
1626 | /* Calculate "eclosure" for all the node in DFA. */ | ||
1627 | |||
1628 | static reg_errcode_t | ||
1629 | calc_eclosure (re_dfa_t *dfa) | ||
1630 | { | ||
1631 | Idx node_idx; | ||
1632 | bool incomplete; | ||
1633 | #ifdef DEBUG | ||
1634 | assert (dfa->nodes_len > 0); | ||
1635 | #endif | ||
1636 | incomplete = false; | ||
1637 | /* For each nodes, calculate epsilon closure. */ | ||
1638 | for (node_idx = 0; ; ++node_idx) | ||
1639 | { | ||
1640 | reg_errcode_t err; | ||
1641 | re_node_set eclosure_elem; | ||
1642 | if (node_idx == dfa->nodes_len) | ||
1643 | { | ||
1644 | if (!incomplete) | ||
1645 | break; | ||
1646 | incomplete = false; | ||
1647 | node_idx = 0; | ||
1648 | } | ||
1649 | |||
1650 | #ifdef DEBUG | ||
1651 | assert (dfa->eclosures[node_idx].nelem != REG_MISSING); | ||
1652 | #endif | ||
1653 | |||
1654 | /* If we have already calculated, skip it. */ | ||
1655 | if (dfa->eclosures[node_idx].nelem != 0) | ||
1656 | continue; | ||
1657 | /* Calculate epsilon closure of `node_idx'. */ | ||
1658 | err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, true); | ||
1659 | if (BE (err != REG_NOERROR, 0)) | ||
1660 | return err; | ||
1661 | |||
1662 | if (dfa->eclosures[node_idx].nelem == 0) | ||
1663 | { | ||
1664 | incomplete = true; | ||
1665 | re_node_set_free (&eclosure_elem); | ||
1666 | } | ||
1667 | } | ||
1668 | return REG_NOERROR; | ||
1669 | } | ||
1670 | |||
1671 | /* Calculate epsilon closure of NODE. */ | ||
1672 | |||
1673 | static reg_errcode_t | ||
1674 | calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root) | ||
1675 | { | ||
1676 | reg_errcode_t err; | ||
1677 | unsigned int constraint; | ||
1678 | Idx i; | ||
1679 | bool incomplete; | ||
1680 | bool ok; | ||
1681 | re_node_set eclosure; | ||
1682 | incomplete = false; | ||
1683 | err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1); | ||
1684 | if (BE (err != REG_NOERROR, 0)) | ||
1685 | return err; | ||
1686 | |||
1687 | /* This indicates that we are calculating this node now. | ||
1688 | We reference this value to avoid infinite loop. */ | ||
1689 | dfa->eclosures[node].nelem = REG_MISSING; | ||
1690 | |||
1691 | constraint = ((dfa->nodes[node].type == ANCHOR) | ||
1692 | ? dfa->nodes[node].opr.ctx_type : 0); | ||
1693 | /* If the current node has constraints, duplicate all nodes. | ||
1694 | Since they must inherit the constraints. */ | ||
1695 | if (constraint | ||
1696 | && dfa->edests[node].nelem | ||
1697 | && !dfa->nodes[dfa->edests[node].elems[0]].duplicated) | ||
1698 | { | ||
1699 | err = duplicate_node_closure (dfa, node, node, node, constraint); | ||
1700 | if (BE (err != REG_NOERROR, 0)) | ||
1701 | return err; | ||
1702 | } | ||
1703 | |||
1704 | /* Expand each epsilon destination nodes. */ | ||
1705 | if (IS_EPSILON_NODE(dfa->nodes[node].type)) | ||
1706 | for (i = 0; i < dfa->edests[node].nelem; ++i) | ||
1707 | { | ||
1708 | re_node_set eclosure_elem; | ||
1709 | Idx edest = dfa->edests[node].elems[i]; | ||
1710 | /* If calculating the epsilon closure of `edest' is in progress, | ||
1711 | return intermediate result. */ | ||
1712 | if (dfa->eclosures[edest].nelem == REG_MISSING) | ||
1713 | { | ||
1714 | incomplete = true; | ||
1715 | continue; | ||
1716 | } | ||
1717 | /* If we haven't calculated the epsilon closure of `edest' yet, | ||
1718 | calculate now. Otherwise use calculated epsilon closure. */ | ||
1719 | if (dfa->eclosures[edest].nelem == 0) | ||
1720 | { | ||
1721 | err = calc_eclosure_iter (&eclosure_elem, dfa, edest, false); | ||
1722 | if (BE (err != REG_NOERROR, 0)) | ||
1723 | return err; | ||
1724 | } | ||
1725 | else | ||
1726 | eclosure_elem = dfa->eclosures[edest]; | ||
1727 | /* Merge the epsilon closure of `edest'. */ | ||
1728 | re_node_set_merge (&eclosure, &eclosure_elem); | ||
1729 | /* If the epsilon closure of `edest' is incomplete, | ||
1730 | the epsilon closure of this node is also incomplete. */ | ||
1731 | if (dfa->eclosures[edest].nelem == 0) | ||
1732 | { | ||
1733 | incomplete = true; | ||
1734 | re_node_set_free (&eclosure_elem); | ||
1735 | } | ||
1736 | } | ||
1737 | |||
1738 | /* Epsilon closures include itself. */ | ||
1739 | ok = re_node_set_insert (&eclosure, node); | ||
1740 | if (BE (! ok, 0)) | ||
1741 | return REG_ESPACE; | ||
1742 | if (incomplete && !root) | ||
1743 | dfa->eclosures[node].nelem = 0; | ||
1744 | else | ||
1745 | dfa->eclosures[node] = eclosure; | ||
1746 | *new_set = eclosure; | ||
1747 | return REG_NOERROR; | ||
1748 | } | ||
1749 | |||
1750 | /* Functions for token which are used in the parser. */ | ||
1751 | |||
1752 | /* Fetch a token from INPUT. | ||
1753 | We must not use this function inside bracket expressions. */ | ||
1754 | |||
1755 | static void | ||
1756 | internal_function | ||
1757 | fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax) | ||
1758 | { | ||
1759 | re_string_skip_bytes (input, peek_token (result, input, syntax)); | ||
1760 | } | ||
1761 | |||
1762 | /* Peek a token from INPUT, and return the length of the token. | ||
1763 | We must not use this function inside bracket expressions. */ | ||
1764 | |||
1765 | static int | ||
1766 | internal_function | ||
1767 | peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax) | ||
1768 | { | ||
1769 | unsigned char c; | ||
1770 | |||
1771 | if (re_string_eoi (input)) | ||
1772 | { | ||
1773 | token->type = END_OF_RE; | ||
1774 | return 0; | ||
1775 | } | ||
1776 | |||
1777 | c = re_string_peek_byte (input, 0); | ||
1778 | token->opr.c = c; | ||
1779 | |||
1780 | token->word_char = 0; | ||
1781 | #ifdef RE_ENABLE_I18N | ||
1782 | token->mb_partial = 0; | ||
1783 | if (input->mb_cur_max > 1 && | ||
1784 | !re_string_first_byte (input, re_string_cur_idx (input))) | ||
1785 | { | ||
1786 | token->type = CHARACTER; | ||
1787 | token->mb_partial = 1; | ||
1788 | return 1; | ||
1789 | } | ||
1790 | #endif | ||
1791 | if (c == '\\') | ||
1792 | { | ||
1793 | unsigned char c2; | ||
1794 | if (re_string_cur_idx (input) + 1 >= re_string_length (input)) | ||
1795 | { | ||
1796 | token->type = BACK_SLASH; | ||
1797 | return 1; | ||
1798 | } | ||
1799 | |||
1800 | c2 = re_string_peek_byte_case (input, 1); | ||
1801 | token->opr.c = c2; | ||
1802 | token->type = CHARACTER; | ||
1803 | #ifdef RE_ENABLE_I18N | ||
1804 | if (input->mb_cur_max > 1) | ||
1805 | { | ||
1806 | wint_t wc = re_string_wchar_at (input, | ||
1807 | re_string_cur_idx (input) + 1); | ||
1808 | token->word_char = IS_WIDE_WORD_CHAR (wc) != 0; | ||
1809 | } | ||
1810 | else | ||
1811 | #endif | ||
1812 | token->word_char = IS_WORD_CHAR (c2) != 0; | ||
1813 | |||
1814 | switch (c2) | ||
1815 | { | ||
1816 | case '|': | ||
1817 | if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR)) | ||
1818 | token->type = OP_ALT; | ||
1819 | break; | ||
1820 | case '1': case '2': case '3': case '4': case '5': | ||
1821 | case '6': case '7': case '8': case '9': | ||
1822 | if (!(syntax & RE_NO_BK_REFS)) | ||
1823 | { | ||
1824 | token->type = OP_BACK_REF; | ||
1825 | token->opr.idx = c2 - '1'; | ||
1826 | } | ||
1827 | break; | ||
1828 | case '<': | ||
1829 | if (!(syntax & RE_NO_GNU_OPS)) | ||
1830 | { | ||
1831 | token->type = ANCHOR; | ||
1832 | token->opr.ctx_type = WORD_FIRST; | ||
1833 | } | ||
1834 | break; | ||
1835 | case '>': | ||
1836 | if (!(syntax & RE_NO_GNU_OPS)) | ||
1837 | { | ||
1838 | token->type = ANCHOR; | ||
1839 | token->opr.ctx_type = WORD_LAST; | ||
1840 | } | ||
1841 | break; | ||
1842 | case 'b': | ||
1843 | if (!(syntax & RE_NO_GNU_OPS)) | ||
1844 | { | ||
1845 | token->type = ANCHOR; | ||
1846 | token->opr.ctx_type = WORD_DELIM; | ||
1847 | } | ||
1848 | break; | ||
1849 | case 'B': | ||
1850 | if (!(syntax & RE_NO_GNU_OPS)) | ||
1851 | { | ||
1852 | token->type = ANCHOR; | ||
1853 | token->opr.ctx_type = NOT_WORD_DELIM; | ||
1854 | } | ||
1855 | break; | ||
1856 | case 'w': | ||
1857 | if (!(syntax & RE_NO_GNU_OPS)) | ||
1858 | token->type = OP_WORD; | ||
1859 | break; | ||
1860 | case 'W': | ||
1861 | if (!(syntax & RE_NO_GNU_OPS)) | ||
1862 | token->type = OP_NOTWORD; | ||
1863 | break; | ||
1864 | case 's': | ||
1865 | if (!(syntax & RE_NO_GNU_OPS)) | ||
1866 | token->type = OP_SPACE; | ||
1867 | break; | ||
1868 | case 'S': | ||
1869 | if (!(syntax & RE_NO_GNU_OPS)) | ||
1870 | token->type = OP_NOTSPACE; | ||
1871 | break; | ||
1872 | case '`': | ||
1873 | if (!(syntax & RE_NO_GNU_OPS)) | ||
1874 | { | ||
1875 | token->type = ANCHOR; | ||
1876 | token->opr.ctx_type = BUF_FIRST; | ||
1877 | } | ||
1878 | break; | ||
1879 | case '\'': | ||
1880 | if (!(syntax & RE_NO_GNU_OPS)) | ||
1881 | { | ||
1882 | token->type = ANCHOR; | ||
1883 | token->opr.ctx_type = BUF_LAST; | ||
1884 | } | ||
1885 | break; | ||
1886 | case '(': | ||
1887 | if (!(syntax & RE_NO_BK_PARENS)) | ||
1888 | token->type = OP_OPEN_SUBEXP; | ||
1889 | break; | ||
1890 | case ')': | ||
1891 | if (!(syntax & RE_NO_BK_PARENS)) | ||
1892 | token->type = OP_CLOSE_SUBEXP; | ||
1893 | break; | ||
1894 | case '+': | ||
1895 | if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) | ||
1896 | token->type = OP_DUP_PLUS; | ||
1897 | break; | ||
1898 | case '?': | ||
1899 | if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) | ||
1900 | token->type = OP_DUP_QUESTION; | ||
1901 | break; | ||
1902 | case '{': | ||
1903 | if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) | ||
1904 | token->type = OP_OPEN_DUP_NUM; | ||
1905 | break; | ||
1906 | case '}': | ||
1907 | if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) | ||
1908 | token->type = OP_CLOSE_DUP_NUM; | ||
1909 | break; | ||
1910 | default: | ||
1911 | break; | ||
1912 | } | ||
1913 | return 2; | ||
1914 | } | ||
1915 | |||
1916 | token->type = CHARACTER; | ||
1917 | #ifdef RE_ENABLE_I18N | ||
1918 | if (input->mb_cur_max > 1) | ||
1919 | { | ||
1920 | wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input)); | ||
1921 | token->word_char = IS_WIDE_WORD_CHAR (wc) != 0; | ||
1922 | } | ||
1923 | else | ||
1924 | #endif | ||
1925 | token->word_char = IS_WORD_CHAR (token->opr.c); | ||
1926 | |||
1927 | switch (c) | ||
1928 | { | ||
1929 | case '\n': | ||
1930 | if (syntax & RE_NEWLINE_ALT) | ||
1931 | token->type = OP_ALT; | ||
1932 | break; | ||
1933 | case '|': | ||
1934 | if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR)) | ||
1935 | token->type = OP_ALT; | ||
1936 | break; | ||
1937 | case '*': | ||
1938 | token->type = OP_DUP_ASTERISK; | ||
1939 | break; | ||
1940 | case '+': | ||
1941 | if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) | ||
1942 | token->type = OP_DUP_PLUS; | ||
1943 | break; | ||
1944 | case '?': | ||
1945 | if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) | ||
1946 | token->type = OP_DUP_QUESTION; | ||
1947 | break; | ||
1948 | case '{': | ||
1949 | if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) | ||
1950 | token->type = OP_OPEN_DUP_NUM; | ||
1951 | break; | ||
1952 | case '}': | ||
1953 | if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) | ||
1954 | token->type = OP_CLOSE_DUP_NUM; | ||
1955 | break; | ||
1956 | case '(': | ||
1957 | if (syntax & RE_NO_BK_PARENS) | ||
1958 | token->type = OP_OPEN_SUBEXP; | ||
1959 | break; | ||
1960 | case ')': | ||
1961 | if (syntax & RE_NO_BK_PARENS) | ||
1962 | token->type = OP_CLOSE_SUBEXP; | ||
1963 | break; | ||
1964 | case '[': | ||
1965 | token->type = OP_OPEN_BRACKET; | ||
1966 | break; | ||
1967 | case '.': | ||
1968 | token->type = OP_PERIOD; | ||
1969 | break; | ||
1970 | case '^': | ||
1971 | if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) && | ||
1972 | re_string_cur_idx (input) != 0) | ||
1973 | { | ||
1974 | char prev = re_string_peek_byte (input, -1); | ||
1975 | if (!(syntax & RE_NEWLINE_ALT) || prev != '\n') | ||
1976 | break; | ||
1977 | } | ||
1978 | token->type = ANCHOR; | ||
1979 | token->opr.ctx_type = LINE_FIRST; | ||
1980 | break; | ||
1981 | case '$': | ||
1982 | if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && | ||
1983 | re_string_cur_idx (input) + 1 != re_string_length (input)) | ||
1984 | { | ||
1985 | re_token_t next; | ||
1986 | re_string_skip_bytes (input, 1); | ||
1987 | peek_token (&next, input, syntax); | ||
1988 | re_string_skip_bytes (input, -1); | ||
1989 | if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP) | ||
1990 | break; | ||
1991 | } | ||
1992 | token->type = ANCHOR; | ||
1993 | token->opr.ctx_type = LINE_LAST; | ||
1994 | break; | ||
1995 | default: | ||
1996 | break; | ||
1997 | } | ||
1998 | return 1; | ||
1999 | } | ||
2000 | |||
2001 | /* Peek a token from INPUT, and return the length of the token. | ||
2002 | We must not use this function out of bracket expressions. */ | ||
2003 | |||
2004 | static int | ||
2005 | internal_function | ||
2006 | peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax) | ||
2007 | { | ||
2008 | unsigned char c; | ||
2009 | if (re_string_eoi (input)) | ||
2010 | { | ||
2011 | token->type = END_OF_RE; | ||
2012 | return 0; | ||
2013 | } | ||
2014 | c = re_string_peek_byte (input, 0); | ||
2015 | token->opr.c = c; | ||
2016 | |||
2017 | #ifdef RE_ENABLE_I18N | ||
2018 | if (input->mb_cur_max > 1 && | ||
2019 | !re_string_first_byte (input, re_string_cur_idx (input))) | ||
2020 | { | ||
2021 | token->type = CHARACTER; | ||
2022 | return 1; | ||
2023 | } | ||
2024 | #endif /* RE_ENABLE_I18N */ | ||
2025 | |||
2026 | if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) | ||
2027 | && re_string_cur_idx (input) + 1 < re_string_length (input)) | ||
2028 | { | ||
2029 | /* In this case, '\' escape a character. */ | ||
2030 | unsigned char c2; | ||
2031 | re_string_skip_bytes (input, 1); | ||
2032 | c2 = re_string_peek_byte (input, 0); | ||
2033 | token->opr.c = c2; | ||
2034 | token->type = CHARACTER; | ||
2035 | return 1; | ||
2036 | } | ||
2037 | if (c == '[') /* '[' is a special char in a bracket exps. */ | ||
2038 | { | ||
2039 | unsigned char c2; | ||
2040 | int token_len; | ||
2041 | if (re_string_cur_idx (input) + 1 < re_string_length (input)) | ||
2042 | c2 = re_string_peek_byte (input, 1); | ||
2043 | else | ||
2044 | c2 = 0; | ||
2045 | token->opr.c = c2; | ||
2046 | token_len = 2; | ||
2047 | switch (c2) | ||
2048 | { | ||
2049 | case '.': | ||
2050 | token->type = OP_OPEN_COLL_ELEM; | ||
2051 | break; | ||
2052 | case '=': | ||
2053 | token->type = OP_OPEN_EQUIV_CLASS; | ||
2054 | break; | ||
2055 | case ':': | ||
2056 | if (syntax & RE_CHAR_CLASSES) | ||
2057 | { | ||
2058 | token->type = OP_OPEN_CHAR_CLASS; | ||
2059 | break; | ||
2060 | } | ||
2061 | /* else fall through. */ | ||
2062 | default: | ||
2063 | token->type = CHARACTER; | ||
2064 | token->opr.c = c; | ||
2065 | token_len = 1; | ||
2066 | break; | ||
2067 | } | ||
2068 | return token_len; | ||
2069 | } | ||
2070 | switch (c) | ||
2071 | { | ||
2072 | case '-': | ||
2073 | token->type = OP_CHARSET_RANGE; | ||
2074 | break; | ||
2075 | case ']': | ||
2076 | token->type = OP_CLOSE_BRACKET; | ||
2077 | break; | ||
2078 | case '^': | ||
2079 | token->type = OP_NON_MATCH_LIST; | ||
2080 | break; | ||
2081 | default: | ||
2082 | token->type = CHARACTER; | ||
2083 | } | ||
2084 | return 1; | ||
2085 | } | ||
2086 | |||
2087 | /* Functions for parser. */ | ||
2088 | |||
2089 | /* Entry point of the parser. | ||
2090 | Parse the regular expression REGEXP and return the structure tree. | ||
2091 | If an error is occured, ERR is set by error code, and return NULL. | ||
2092 | This function build the following tree, from regular expression <reg_exp>: | ||
2093 | CAT | ||
2094 | / \ | ||
2095 | / \ | ||
2096 | <reg_exp> EOR | ||
2097 | |||
2098 | CAT means concatenation. | ||
2099 | EOR means end of regular expression. */ | ||
2100 | |||
2101 | static bin_tree_t * | ||
2102 | parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, | ||
2103 | reg_errcode_t *err) | ||
2104 | { | ||
2105 | re_dfa_t *dfa = (re_dfa_t *) preg->buffer; | ||
2106 | bin_tree_t *tree, *eor, *root; | ||
2107 | re_token_t current_token; | ||
2108 | dfa->syntax = syntax; | ||
2109 | fetch_token (¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE); | ||
2110 | tree = parse_reg_exp (regexp, preg, ¤t_token, syntax, 0, err); | ||
2111 | if (BE (*err != REG_NOERROR && tree == NULL, 0)) | ||
2112 | return NULL; | ||
2113 | eor = create_tree (dfa, NULL, NULL, END_OF_RE); | ||
2114 | if (tree != NULL) | ||
2115 | root = create_tree (dfa, tree, eor, CONCAT); | ||
2116 | else | ||
2117 | root = eor; | ||
2118 | if (BE (eor == NULL || root == NULL, 0)) | ||
2119 | { | ||
2120 | *err = REG_ESPACE; | ||
2121 | return NULL; | ||
2122 | } | ||
2123 | return root; | ||
2124 | } | ||
2125 | |||
2126 | /* This function build the following tree, from regular expression | ||
2127 | <branch1>|<branch2>: | ||
2128 | ALT | ||
2129 | / \ | ||
2130 | / \ | ||
2131 | <branch1> <branch2> | ||
2132 | |||
2133 | ALT means alternative, which represents the operator `|'. */ | ||
2134 | |||
2135 | static bin_tree_t * | ||
2136 | parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, | ||
2137 | reg_syntax_t syntax, Idx nest, reg_errcode_t *err) | ||
2138 | { | ||
2139 | re_dfa_t *dfa = (re_dfa_t *) preg->buffer; | ||
2140 | bin_tree_t *tree, *branch = NULL; | ||
2141 | tree = parse_branch (regexp, preg, token, syntax, nest, err); | ||
2142 | if (BE (*err != REG_NOERROR && tree == NULL, 0)) | ||
2143 | return NULL; | ||
2144 | |||
2145 | while (token->type == OP_ALT) | ||
2146 | { | ||
2147 | fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); | ||
2148 | if (token->type != OP_ALT && token->type != END_OF_RE | ||
2149 | && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) | ||
2150 | { | ||
2151 | branch = parse_branch (regexp, preg, token, syntax, nest, err); | ||
2152 | if (BE (*err != REG_NOERROR && branch == NULL, 0)) | ||
2153 | return NULL; | ||
2154 | } | ||
2155 | else | ||
2156 | branch = NULL; | ||
2157 | tree = create_tree (dfa, tree, branch, OP_ALT); | ||
2158 | if (BE (tree == NULL, 0)) | ||
2159 | { | ||
2160 | *err = REG_ESPACE; | ||
2161 | return NULL; | ||
2162 | } | ||
2163 | } | ||
2164 | return tree; | ||
2165 | } | ||
2166 | |||
2167 | /* This function build the following tree, from regular expression | ||
2168 | <exp1><exp2>: | ||
2169 | CAT | ||
2170 | / \ | ||
2171 | / \ | ||
2172 | <exp1> <exp2> | ||
2173 | |||
2174 | CAT means concatenation. */ | ||
2175 | |||
2176 | static bin_tree_t * | ||
2177 | parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token, | ||
2178 | reg_syntax_t syntax, Idx nest, reg_errcode_t *err) | ||
2179 | { | ||
2180 | bin_tree_t *tree, *expr; | ||
2181 | re_dfa_t *dfa = (re_dfa_t *) preg->buffer; | ||
2182 | tree = parse_expression (regexp, preg, token, syntax, nest, err); | ||
2183 | if (BE (*err != REG_NOERROR && tree == NULL, 0)) | ||
2184 | return NULL; | ||
2185 | |||
2186 | while (token->type != OP_ALT && token->type != END_OF_RE | ||
2187 | && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) | ||
2188 | { | ||
2189 | expr = parse_expression (regexp, preg, token, syntax, nest, err); | ||
2190 | if (BE (*err != REG_NOERROR && expr == NULL, 0)) | ||
2191 | { | ||
2192 | return NULL; | ||
2193 | } | ||
2194 | if (tree != NULL && expr != NULL) | ||
2195 | { | ||
2196 | tree = create_tree (dfa, tree, expr, CONCAT); | ||
2197 | if (tree == NULL) | ||
2198 | { | ||
2199 | *err = REG_ESPACE; | ||
2200 | return NULL; | ||
2201 | } | ||
2202 | } | ||
2203 | else if (tree == NULL) | ||
2204 | tree = expr; | ||
2205 | /* Otherwise expr == NULL, we don't need to create new tree. */ | ||
2206 | } | ||
2207 | return tree; | ||
2208 | } | ||
2209 | |||
2210 | /* This function build the following tree, from regular expression a*: | ||
2211 | * | ||
2212 | | | ||
2213 | a | ||
2214 | */ | ||
2215 | |||
2216 | static bin_tree_t * | ||
2217 | parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token, | ||
2218 | reg_syntax_t syntax, Idx nest, reg_errcode_t *err) | ||
2219 | { | ||
2220 | re_dfa_t *dfa = (re_dfa_t *) preg->buffer; | ||
2221 | bin_tree_t *tree; | ||
2222 | switch (token->type) | ||
2223 | { | ||
2224 | case CHARACTER: | ||
2225 | tree = create_token_tree (dfa, NULL, NULL, token); | ||
2226 | if (BE (tree == NULL, 0)) | ||
2227 | { | ||
2228 | *err = REG_ESPACE; | ||
2229 | return NULL; | ||
2230 | } | ||
2231 | #ifdef RE_ENABLE_I18N | ||
2232 | if (dfa->mb_cur_max > 1) | ||
2233 | { | ||
2234 | while (!re_string_eoi (regexp) | ||
2235 | && !re_string_first_byte (regexp, re_string_cur_idx (regexp))) | ||
2236 | { | ||
2237 | bin_tree_t *mbc_remain; | ||
2238 | fetch_token (token, regexp, syntax); | ||
2239 | mbc_remain = create_token_tree (dfa, NULL, NULL, token); | ||
2240 | tree = create_tree (dfa, tree, mbc_remain, CONCAT); | ||
2241 | if (BE (mbc_remain == NULL || tree == NULL, 0)) | ||
2242 | { | ||
2243 | *err = REG_ESPACE; | ||
2244 | return NULL; | ||
2245 | } | ||
2246 | } | ||
2247 | } | ||
2248 | #endif | ||
2249 | break; | ||
2250 | case OP_OPEN_SUBEXP: | ||
2251 | tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err); | ||
2252 | if (BE (*err != REG_NOERROR && tree == NULL, 0)) | ||
2253 | return NULL; | ||
2254 | break; | ||
2255 | case OP_OPEN_BRACKET: | ||
2256 | tree = parse_bracket_exp (regexp, dfa, token, syntax, err); | ||
2257 | if (BE (*err != REG_NOERROR && tree == NULL, 0)) | ||
2258 | return NULL; | ||
2259 | break; | ||
2260 | case OP_BACK_REF: | ||
2261 | if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1)) | ||
2262 | { | ||
2263 | *err = REG_ESUBREG; | ||
2264 | return NULL; | ||
2265 | } | ||
2266 | dfa->used_bkref_map |= 1 << token->opr.idx; | ||
2267 | tree = create_token_tree (dfa, NULL, NULL, token); | ||
2268 | if (BE (tree == NULL, 0)) | ||
2269 | { | ||
2270 | *err = REG_ESPACE; | ||
2271 | return NULL; | ||
2272 | } | ||
2273 | ++dfa->nbackref; | ||
2274 | dfa->has_mb_node = 1; | ||
2275 | break; | ||
2276 | case OP_OPEN_DUP_NUM: | ||
2277 | if (syntax & RE_CONTEXT_INVALID_DUP) | ||
2278 | { | ||
2279 | *err = REG_BADRPT; | ||
2280 | return NULL; | ||
2281 | } | ||
2282 | /* FALLTHROUGH */ | ||
2283 | case OP_DUP_ASTERISK: | ||
2284 | case OP_DUP_PLUS: | ||
2285 | case OP_DUP_QUESTION: | ||
2286 | if (syntax & RE_CONTEXT_INVALID_OPS) | ||
2287 | { | ||
2288 | *err = REG_BADRPT; | ||
2289 | return NULL; | ||
2290 | } | ||
2291 | else if (syntax & RE_CONTEXT_INDEP_OPS) | ||
2292 | { | ||
2293 | fetch_token (token, regexp, syntax); | ||
2294 | return parse_expression (regexp, preg, token, syntax, nest, err); | ||
2295 | } | ||
2296 | /* else fall through */ | ||
2297 | case OP_CLOSE_SUBEXP: | ||
2298 | if ((token->type == OP_CLOSE_SUBEXP) && | ||
2299 | !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)) | ||
2300 | { | ||
2301 | *err = REG_ERPAREN; | ||
2302 | return NULL; | ||
2303 | } | ||
2304 | /* else fall through */ | ||
2305 | case OP_CLOSE_DUP_NUM: | ||
2306 | /* We treat it as a normal character. */ | ||
2307 | |||
2308 | /* Then we can these characters as normal characters. */ | ||
2309 | token->type = CHARACTER; | ||
2310 | /* mb_partial and word_char bits should be initialized already | ||
2311 | by peek_token. */ | ||
2312 | tree = create_token_tree (dfa, NULL, NULL, token); | ||
2313 | if (BE (tree == NULL, 0)) | ||
2314 | { | ||
2315 | *err = REG_ESPACE; | ||
2316 | return NULL; | ||
2317 | } | ||
2318 | break; | ||
2319 | case ANCHOR: | ||
2320 | if ((token->opr.ctx_type | ||
2321 | & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST)) | ||
2322 | && dfa->word_ops_used == 0) | ||
2323 | init_word_char (dfa); | ||
2324 | if (token->opr.ctx_type == WORD_DELIM | ||
2325 | || token->opr.ctx_type == NOT_WORD_DELIM) | ||
2326 | { | ||
2327 | bin_tree_t *tree_first, *tree_last; | ||
2328 | if (token->opr.ctx_type == WORD_DELIM) | ||
2329 | { | ||
2330 | token->opr.ctx_type = WORD_FIRST; | ||
2331 | tree_first = create_token_tree (dfa, NULL, NULL, token); | ||
2332 | token->opr.ctx_type = WORD_LAST; | ||
2333 | } | ||
2334 | else | ||
2335 | { | ||
2336 | token->opr.ctx_type = INSIDE_WORD; | ||
2337 | tree_first = create_token_tree (dfa, NULL, NULL, token); | ||
2338 | token->opr.ctx_type = INSIDE_NOTWORD; | ||
2339 | } | ||
2340 | tree_last = create_token_tree (dfa, NULL, NULL, token); | ||
2341 | tree = create_tree (dfa, tree_first, tree_last, OP_ALT); | ||
2342 | if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0)) | ||
2343 | { | ||
2344 | *err = REG_ESPACE; | ||
2345 | return NULL; | ||
2346 | } | ||
2347 | } | ||
2348 | else | ||
2349 | { | ||
2350 | tree = create_token_tree (dfa, NULL, NULL, token); | ||
2351 | if (BE (tree == NULL, 0)) | ||
2352 | { | ||
2353 | *err = REG_ESPACE; | ||
2354 | return NULL; | ||
2355 | } | ||
2356 | } | ||
2357 | /* We must return here, since ANCHORs can't be followed | ||
2358 | by repetition operators. | ||
2359 | eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>", | ||
2360 | it must not be "<ANCHOR(^)><REPEAT(*)>". */ | ||
2361 | fetch_token (token, regexp, syntax); | ||
2362 | return tree; | ||
2363 | case OP_PERIOD: | ||
2364 | tree = create_token_tree (dfa, NULL, NULL, token); | ||
2365 | if (BE (tree == NULL, 0)) | ||
2366 | { | ||
2367 | *err = REG_ESPACE; | ||
2368 | return NULL; | ||
2369 | } | ||
2370 | if (dfa->mb_cur_max > 1) | ||
2371 | dfa->has_mb_node = 1; | ||
2372 | break; | ||
2373 | case OP_WORD: | ||
2374 | case OP_NOTWORD: | ||
2375 | tree = build_charclass_op (dfa, regexp->trans, | ||
2376 | (const unsigned char *) "alnum", | ||
2377 | (const unsigned char *) "_", | ||
2378 | token->type == OP_NOTWORD, err); | ||
2379 | if (BE (*err != REG_NOERROR && tree == NULL, 0)) | ||
2380 | return NULL; | ||
2381 | break; | ||
2382 | case OP_SPACE: | ||
2383 | case OP_NOTSPACE: | ||
2384 | tree = build_charclass_op (dfa, regexp->trans, | ||
2385 | (const unsigned char *) "space", | ||
2386 | (const unsigned char *) "", | ||
2387 | token->type == OP_NOTSPACE, err); | ||
2388 | if (BE (*err != REG_NOERROR && tree == NULL, 0)) | ||
2389 | return NULL; | ||
2390 | break; | ||
2391 | case OP_ALT: | ||
2392 | case END_OF_RE: | ||
2393 | return NULL; | ||
2394 | case BACK_SLASH: | ||
2395 | *err = REG_EESCAPE; | ||
2396 | return NULL; | ||
2397 | default: | ||
2398 | /* Must not happen? */ | ||
2399 | #ifdef DEBUG | ||
2400 | assert (0); | ||
2401 | #endif | ||
2402 | return NULL; | ||
2403 | } | ||
2404 | fetch_token (token, regexp, syntax); | ||
2405 | |||
2406 | while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS | ||
2407 | || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM) | ||
2408 | { | ||
2409 | tree = parse_dup_op (tree, regexp, dfa, token, syntax, err); | ||
2410 | if (BE (*err != REG_NOERROR && tree == NULL, 0)) | ||
2411 | return NULL; | ||
2412 | /* In BRE consecutive duplications are not allowed. */ | ||
2413 | if ((syntax & RE_CONTEXT_INVALID_DUP) | ||
2414 | && (token->type == OP_DUP_ASTERISK | ||
2415 | || token->type == OP_OPEN_DUP_NUM)) | ||
2416 | { | ||
2417 | *err = REG_BADRPT; | ||
2418 | return NULL; | ||
2419 | } | ||
2420 | } | ||
2421 | |||
2422 | return tree; | ||
2423 | } | ||
2424 | |||
2425 | /* This function build the following tree, from regular expression | ||
2426 | (<reg_exp>): | ||
2427 | SUBEXP | ||
2428 | | | ||
2429 | <reg_exp> | ||
2430 | */ | ||
2431 | |||
2432 | static bin_tree_t * | ||
2433 | parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, | ||
2434 | reg_syntax_t syntax, Idx nest, reg_errcode_t *err) | ||
2435 | { | ||
2436 | re_dfa_t *dfa = (re_dfa_t *) preg->buffer; | ||
2437 | bin_tree_t *tree; | ||
2438 | size_t cur_nsub; | ||
2439 | cur_nsub = preg->re_nsub++; | ||
2440 | |||
2441 | fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); | ||
2442 | |||
2443 | /* The subexpression may be a null string. */ | ||
2444 | if (token->type == OP_CLOSE_SUBEXP) | ||
2445 | tree = NULL; | ||
2446 | else | ||
2447 | { | ||
2448 | tree = parse_reg_exp (regexp, preg, token, syntax, nest, err); | ||
2449 | if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0)) | ||
2450 | *err = REG_EPAREN; | ||
2451 | if (BE (*err != REG_NOERROR, 0)) | ||
2452 | return NULL; | ||
2453 | } | ||
2454 | |||
2455 | if (cur_nsub <= '9' - '1') | ||
2456 | dfa->completed_bkref_map |= 1 << cur_nsub; | ||
2457 | |||
2458 | tree = create_tree (dfa, tree, NULL, SUBEXP); | ||
2459 | if (BE (tree == NULL, 0)) | ||
2460 | { | ||
2461 | *err = REG_ESPACE; | ||
2462 | return NULL; | ||
2463 | } | ||
2464 | tree->token.opr.idx = cur_nsub; | ||
2465 | return tree; | ||
2466 | } | ||
2467 | |||
2468 | /* This function parse repetition operators like "*", "+", "{1,3}" etc. */ | ||
2469 | |||
2470 | static bin_tree_t * | ||
2471 | parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa, | ||
2472 | re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err) | ||
2473 | { | ||
2474 | bin_tree_t *tree = NULL, *old_tree = NULL; | ||
2475 | Idx i, start, end, start_idx = re_string_cur_idx (regexp); | ||
2476 | re_token_t start_token = *token; | ||
2477 | |||
2478 | if (token->type == OP_OPEN_DUP_NUM) | ||
2479 | { | ||
2480 | end = 0; | ||
2481 | start = fetch_number (regexp, token, syntax); | ||
2482 | if (start == REG_MISSING) | ||
2483 | { | ||
2484 | if (token->type == CHARACTER && token->opr.c == ',') | ||
2485 | start = 0; /* We treat "{,m}" as "{0,m}". */ | ||
2486 | else | ||
2487 | { | ||
2488 | *err = REG_BADBR; /* <re>{} is invalid. */ | ||
2489 | return NULL; | ||
2490 | } | ||
2491 | } | ||
2492 | if (BE (start != REG_ERROR, 1)) | ||
2493 | { | ||
2494 | /* We treat "{n}" as "{n,n}". */ | ||
2495 | end = ((token->type == OP_CLOSE_DUP_NUM) ? start | ||
2496 | : ((token->type == CHARACTER && token->opr.c == ',') | ||
2497 | ? fetch_number (regexp, token, syntax) : REG_ERROR)); | ||
2498 | } | ||
2499 | if (BE (start == REG_ERROR || end == REG_ERROR, 0)) | ||
2500 | { | ||
2501 | /* Invalid sequence. */ | ||
2502 | if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) | ||
2503 | { | ||
2504 | if (token->type == END_OF_RE) | ||
2505 | *err = REG_EBRACE; | ||
2506 | else | ||
2507 | *err = REG_BADBR; | ||
2508 | |||
2509 | return NULL; | ||
2510 | } | ||
2511 | |||
2512 | /* If the syntax bit is set, rollback. */ | ||
2513 | re_string_set_index (regexp, start_idx); | ||
2514 | *token = start_token; | ||
2515 | token->type = CHARACTER; | ||
2516 | /* mb_partial and word_char bits should be already initialized by | ||
2517 | peek_token. */ | ||
2518 | return elem; | ||
2519 | } | ||
2520 | |||
2521 | if (BE (end != REG_MISSING && start > end, 0)) | ||
2522 | { | ||
2523 | /* First number greater than second. */ | ||
2524 | *err = REG_BADBR; | ||
2525 | return NULL; | ||
2526 | } | ||
2527 | } | ||
2528 | else | ||
2529 | { | ||
2530 | start = (token->type == OP_DUP_PLUS) ? 1 : 0; | ||
2531 | end = (token->type == OP_DUP_QUESTION) ? 1 : REG_MISSING; | ||
2532 | } | ||
2533 | |||
2534 | fetch_token (token, regexp, syntax); | ||
2535 | |||
2536 | if (BE (elem == NULL, 0)) | ||
2537 | return NULL; | ||
2538 | if (BE (start == 0 && end == 0, 0)) | ||
2539 | { | ||
2540 | postorder (elem, free_tree, NULL); | ||
2541 | return NULL; | ||
2542 | } | ||
2543 | |||
2544 | /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */ | ||
2545 | if (BE (start > 0, 0)) | ||
2546 | { | ||
2547 | tree = elem; | ||
2548 | for (i = 2; i <= start; ++i) | ||
2549 | { | ||
2550 | elem = duplicate_tree (elem, dfa); | ||
2551 | tree = create_tree (dfa, tree, elem, CONCAT); | ||
2552 | if (BE (elem == NULL || tree == NULL, 0)) | ||
2553 | goto parse_dup_op_espace; | ||
2554 | } | ||
2555 | |||
2556 | if (start == end) | ||
2557 | return tree; | ||
2558 | |||
2559 | /* Duplicate ELEM before it is marked optional. */ | ||
2560 | elem = duplicate_tree (elem, dfa); | ||
2561 | old_tree = tree; | ||
2562 | } | ||
2563 | else | ||
2564 | old_tree = NULL; | ||
2565 | |||
2566 | if (elem->token.type == SUBEXP) | ||
2567 | postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx); | ||
2568 | |||
2569 | tree = create_tree (dfa, elem, NULL, | ||
2570 | (end == REG_MISSING ? OP_DUP_ASTERISK : OP_ALT)); | ||
2571 | if (BE (tree == NULL, 0)) | ||
2572 | goto parse_dup_op_espace; | ||
2573 | |||
2574 | /* This loop is actually executed only when end != REG_MISSING, | ||
2575 | to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have | ||
2576 | already created the start+1-th copy. */ | ||
2577 | if ((Idx) -1 < 0 || end != REG_MISSING) | ||
2578 | for (i = start + 2; i <= end; ++i) | ||
2579 | { | ||
2580 | elem = duplicate_tree (elem, dfa); | ||
2581 | tree = create_tree (dfa, tree, elem, CONCAT); | ||
2582 | if (BE (elem == NULL || tree == NULL, 0)) | ||
2583 | goto parse_dup_op_espace; | ||
2584 | |||
2585 | tree = create_tree (dfa, tree, NULL, OP_ALT); | ||
2586 | if (BE (tree == NULL, 0)) | ||
2587 | goto parse_dup_op_espace; | ||
2588 | } | ||
2589 | |||
2590 | if (old_tree) | ||
2591 | tree = create_tree (dfa, old_tree, tree, CONCAT); | ||
2592 | |||
2593 | return tree; | ||
2594 | |||
2595 | parse_dup_op_espace: | ||
2596 | *err = REG_ESPACE; | ||
2597 | return NULL; | ||
2598 | } | ||
2599 | |||
2600 | /* Size of the names for collating symbol/equivalence_class/character_class. | ||
2601 | I'm not sure, but maybe enough. */ | ||
2602 | #define BRACKET_NAME_BUF_SIZE 32 | ||
2603 | |||
2604 | #ifndef _LIBC | ||
2605 | /* Local function for parse_bracket_exp only used in case of NOT _LIBC. | ||
2606 | Build the range expression which starts from START_ELEM, and ends | ||
2607 | at END_ELEM. The result are written to MBCSET and SBCSET. | ||
2608 | RANGE_ALLOC is the allocated size of mbcset->range_starts, and | ||
2609 | mbcset->range_ends, is a pointer argument sinse we may | ||
2610 | update it. */ | ||
2611 | |||
2612 | static reg_errcode_t | ||
2613 | internal_function | ||
2614 | # ifdef RE_ENABLE_I18N | ||
2615 | build_range_exp (bitset_t sbcset, re_charset_t *mbcset, Idx *range_alloc, | ||
2616 | bracket_elem_t *start_elem, bracket_elem_t *end_elem) | ||
2617 | # else /* not RE_ENABLE_I18N */ | ||
2618 | build_range_exp (bitset_t sbcset, bracket_elem_t *start_elem, | ||
2619 | bracket_elem_t *end_elem) | ||
2620 | # endif /* not RE_ENABLE_I18N */ | ||
2621 | { | ||
2622 | unsigned int start_ch, end_ch; | ||
2623 | /* Equivalence Classes and Character Classes can't be a range start/end. */ | ||
2624 | if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS | ||
2625 | || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, | ||
2626 | 0)) | ||
2627 | return REG_ERANGE; | ||
2628 | |||
2629 | /* We can handle no multi character collating elements without libc | ||
2630 | support. */ | ||
2631 | if (BE ((start_elem->type == COLL_SYM | ||
2632 | && strlen ((char *) start_elem->opr.name) > 1) | ||
2633 | || (end_elem->type == COLL_SYM | ||
2634 | && strlen ((char *) end_elem->opr.name) > 1), 0)) | ||
2635 | return REG_ECOLLATE; | ||
2636 | |||
2637 | # ifdef RE_ENABLE_I18N | ||
2638 | { | ||
2639 | wchar_t wc; | ||
2640 | wint_t start_wc; | ||
2641 | wint_t end_wc; | ||
2642 | wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; | ||
2643 | |||
2644 | start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch | ||
2645 | : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] | ||
2646 | : 0)); | ||
2647 | end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch | ||
2648 | : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] | ||
2649 | : 0)); | ||
2650 | start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM) | ||
2651 | ? __btowc (start_ch) : start_elem->opr.wch); | ||
2652 | end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM) | ||
2653 | ? __btowc (end_ch) : end_elem->opr.wch); | ||
2654 | if (start_wc == WEOF || end_wc == WEOF) | ||
2655 | return REG_ECOLLATE; | ||
2656 | cmp_buf[0] = start_wc; | ||
2657 | cmp_buf[4] = end_wc; | ||
2658 | if (wcscoll (cmp_buf, cmp_buf + 4) > 0) | ||
2659 | return REG_ERANGE; | ||
2660 | |||
2661 | /* Got valid collation sequence values, add them as a new entry. | ||
2662 | However, for !_LIBC we have no collation elements: if the | ||
2663 | character set is single byte, the single byte character set | ||
2664 | that we build below suffices. parse_bracket_exp passes | ||
2665 | no MBCSET if dfa->mb_cur_max == 1. */ | ||
2666 | if (mbcset) | ||
2667 | { | ||
2668 | /* Check the space of the arrays. */ | ||
2669 | if (BE (*range_alloc == mbcset->nranges, 0)) | ||
2670 | { | ||
2671 | /* There is not enough space, need realloc. */ | ||
2672 | wchar_t *new_array_start, *new_array_end; | ||
2673 | Idx new_nranges; | ||
2674 | |||
2675 | /* +1 in case of mbcset->nranges is 0. */ | ||
2676 | new_nranges = 2 * mbcset->nranges + 1; | ||
2677 | /* Use realloc since mbcset->range_starts and mbcset->range_ends | ||
2678 | are NULL if *range_alloc == 0. */ | ||
2679 | new_array_start = re_realloc (mbcset->range_starts, wchar_t, | ||
2680 | new_nranges); | ||
2681 | new_array_end = re_realloc (mbcset->range_ends, wchar_t, | ||
2682 | new_nranges); | ||
2683 | |||
2684 | if (BE (new_array_start == NULL || new_array_end == NULL, 0)) | ||
2685 | return REG_ESPACE; | ||
2686 | |||
2687 | mbcset->range_starts = new_array_start; | ||
2688 | mbcset->range_ends = new_array_end; | ||
2689 | *range_alloc = new_nranges; | ||
2690 | } | ||
2691 | |||
2692 | mbcset->range_starts[mbcset->nranges] = start_wc; | ||
2693 | mbcset->range_ends[mbcset->nranges++] = end_wc; | ||
2694 | } | ||
2695 | |||
2696 | /* Build the table for single byte characters. */ | ||
2697 | for (wc = 0; wc < SBC_MAX; ++wc) | ||
2698 | { | ||
2699 | cmp_buf[2] = wc; | ||
2700 | if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 | ||
2701 | && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) | ||
2702 | bitset_set (sbcset, wc); | ||
2703 | } | ||
2704 | } | ||
2705 | # else /* not RE_ENABLE_I18N */ | ||
2706 | { | ||
2707 | unsigned int ch; | ||
2708 | start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch | ||
2709 | : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] | ||
2710 | : 0)); | ||
2711 | end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch | ||
2712 | : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] | ||
2713 | : 0)); | ||
2714 | if (start_ch > end_ch) | ||
2715 | return REG_ERANGE; | ||
2716 | /* Build the table for single byte characters. */ | ||
2717 | for (ch = 0; ch < SBC_MAX; ++ch) | ||
2718 | if (start_ch <= ch && ch <= end_ch) | ||
2719 | bitset_set (sbcset, ch); | ||
2720 | } | ||
2721 | # endif /* not RE_ENABLE_I18N */ | ||
2722 | return REG_NOERROR; | ||
2723 | } | ||
2724 | #endif /* not _LIBC */ | ||
2725 | |||
2726 | #ifndef _LIBC | ||
2727 | /* Helper function for parse_bracket_exp only used in case of NOT _LIBC.. | ||
2728 | Build the collating element which is represented by NAME. | ||
2729 | The result are written to MBCSET and SBCSET. | ||
2730 | COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a | ||
2731 | pointer argument since we may update it. */ | ||
2732 | |||
2733 | static reg_errcode_t | ||
2734 | internal_function | ||
2735 | build_collating_symbol (bitset_t sbcset, | ||
2736 | # ifdef RE_ENABLE_I18N | ||
2737 | re_charset_t *mbcset, Idx *coll_sym_alloc, | ||
2738 | # endif | ||
2739 | const unsigned char *name) | ||
2740 | { | ||
2741 | size_t name_len = strlen ((const char *) name); | ||
2742 | if (BE (name_len != 1, 0)) | ||
2743 | return REG_ECOLLATE; | ||
2744 | else | ||
2745 | { | ||
2746 | bitset_set (sbcset, name[0]); | ||
2747 | return REG_NOERROR; | ||
2748 | } | ||
2749 | } | ||
2750 | #endif /* not _LIBC */ | ||
2751 | |||
2752 | /* This function parse bracket expression like "[abc]", "[a-c]", | ||
2753 | "[[.a-a.]]" etc. */ | ||
2754 | |||
2755 | static bin_tree_t * | ||
2756 | parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, | ||
2757 | reg_syntax_t syntax, reg_errcode_t *err) | ||
2758 | { | ||
2759 | #ifdef _LIBC | ||
2760 | const unsigned char *collseqmb; | ||
2761 | const char *collseqwc; | ||
2762 | uint32_t nrules; | ||
2763 | int32_t table_size; | ||
2764 | const int32_t *symb_table; | ||
2765 | const unsigned char *extra; | ||
2766 | |||
2767 | /* Local function for parse_bracket_exp used in _LIBC environement. | ||
2768 | Seek the collating symbol entry correspondings to NAME. | ||
2769 | Return the index of the symbol in the SYMB_TABLE. */ | ||
2770 | |||
2771 | auto inline int32_t | ||
2772 | __attribute ((always_inline)) | ||
2773 | seek_collating_symbol_entry (name, name_len) | ||
2774 | const unsigned char *name; | ||
2775 | size_t name_len; | ||
2776 | { | ||
2777 | int32_t hash = elem_hash ((const char *) name, name_len); | ||
2778 | int32_t elem = hash % table_size; | ||
2779 | if (symb_table[2 * elem] != 0) | ||
2780 | { | ||
2781 | int32_t second = hash % (table_size - 2) + 1; | ||
2782 | |||
2783 | do | ||
2784 | { | ||
2785 | /* First compare the hashing value. */ | ||
2786 | if (symb_table[2 * elem] == hash | ||
2787 | /* Compare the length of the name. */ | ||
2788 | && name_len == extra[symb_table[2 * elem + 1]] | ||
2789 | /* Compare the name. */ | ||
2790 | && memcmp (name, &extra[symb_table[2 * elem + 1] + 1], | ||
2791 | name_len) == 0) | ||
2792 | { | ||
2793 | /* Yep, this is the entry. */ | ||
2794 | break; | ||
2795 | } | ||
2796 | |||
2797 | /* Next entry. */ | ||
2798 | elem += second; | ||
2799 | } | ||
2800 | while (symb_table[2 * elem] != 0); | ||
2801 | } | ||
2802 | return elem; | ||
2803 | } | ||
2804 | |||
2805 | /* Local function for parse_bracket_exp used in _LIBC environement. | ||
2806 | Look up the collation sequence value of BR_ELEM. | ||
2807 | Return the value if succeeded, UINT_MAX otherwise. */ | ||
2808 | |||
2809 | auto inline unsigned int | ||
2810 | __attribute ((always_inline)) | ||
2811 | lookup_collation_sequence_value (br_elem) | ||
2812 | bracket_elem_t *br_elem; | ||
2813 | { | ||
2814 | if (br_elem->type == SB_CHAR) | ||
2815 | { | ||
2816 | /* | ||
2817 | if (MB_CUR_MAX == 1) | ||
2818 | */ | ||
2819 | if (nrules == 0) | ||
2820 | return collseqmb[br_elem->opr.ch]; | ||
2821 | else | ||
2822 | { | ||
2823 | wint_t wc = __btowc (br_elem->opr.ch); | ||
2824 | return __collseq_table_lookup (collseqwc, wc); | ||
2825 | } | ||
2826 | } | ||
2827 | else if (br_elem->type == MB_CHAR) | ||
2828 | { | ||
2829 | return __collseq_table_lookup (collseqwc, br_elem->opr.wch); | ||
2830 | } | ||
2831 | else if (br_elem->type == COLL_SYM) | ||
2832 | { | ||
2833 | size_t sym_name_len = strlen ((char *) br_elem->opr.name); | ||
2834 | if (nrules != 0) | ||
2835 | { | ||
2836 | int32_t elem, idx; | ||
2837 | elem = seek_collating_symbol_entry (br_elem->opr.name, | ||
2838 | sym_name_len); | ||
2839 | if (symb_table[2 * elem] != 0) | ||
2840 | { | ||
2841 | /* We found the entry. */ | ||
2842 | idx = symb_table[2 * elem + 1]; | ||
2843 | /* Skip the name of collating element name. */ | ||
2844 | idx += 1 + extra[idx]; | ||
2845 | /* Skip the byte sequence of the collating element. */ | ||
2846 | idx += 1 + extra[idx]; | ||
2847 | /* Adjust for the alignment. */ | ||
2848 | idx = (idx + 3) & ~3; | ||
2849 | /* Skip the multibyte collation sequence value. */ | ||
2850 | idx += sizeof (unsigned int); | ||
2851 | /* Skip the wide char sequence of the collating element. */ | ||
2852 | idx += sizeof (unsigned int) * | ||
2853 | (1 + *(unsigned int *) (extra + idx)); | ||
2854 | /* Return the collation sequence value. */ | ||
2855 | return *(unsigned int *) (extra + idx); | ||
2856 | } | ||
2857 | else if (symb_table[2 * elem] == 0 && sym_name_len == 1) | ||
2858 | { | ||
2859 | /* No valid character. Match it as a single byte | ||
2860 | character. */ | ||
2861 | return collseqmb[br_elem->opr.name[0]]; | ||
2862 | } | ||
2863 | } | ||
2864 | else if (sym_name_len == 1) | ||
2865 | return collseqmb[br_elem->opr.name[0]]; | ||
2866 | } | ||
2867 | return UINT_MAX; | ||
2868 | } | ||
2869 | |||
2870 | /* Local function for parse_bracket_exp used in _LIBC environement. | ||
2871 | Build the range expression which starts from START_ELEM, and ends | ||
2872 | at END_ELEM. The result are written to MBCSET and SBCSET. | ||
2873 | RANGE_ALLOC is the allocated size of mbcset->range_starts, and | ||
2874 | mbcset->range_ends, is a pointer argument sinse we may | ||
2875 | update it. */ | ||
2876 | |||
2877 | auto inline reg_errcode_t | ||
2878 | __attribute ((always_inline)) | ||
2879 | build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) | ||
2880 | re_charset_t *mbcset; | ||
2881 | Idx *range_alloc; | ||
2882 | bitset_t sbcset; | ||
2883 | bracket_elem_t *start_elem, *end_elem; | ||
2884 | { | ||
2885 | unsigned int ch; | ||
2886 | uint32_t start_collseq; | ||
2887 | uint32_t end_collseq; | ||
2888 | |||
2889 | /* Equivalence Classes and Character Classes can't be a range | ||
2890 | start/end. */ | ||
2891 | if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS | ||
2892 | || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, | ||
2893 | 0)) | ||
2894 | return REG_ERANGE; | ||
2895 | |||
2896 | start_collseq = lookup_collation_sequence_value (start_elem); | ||
2897 | end_collseq = lookup_collation_sequence_value (end_elem); | ||
2898 | /* Check start/end collation sequence values. */ | ||
2899 | if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0)) | ||
2900 | return REG_ECOLLATE; | ||
2901 | if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0)) | ||
2902 | return REG_ERANGE; | ||
2903 | |||
2904 | /* Got valid collation sequence values, add them as a new entry. | ||
2905 | However, if we have no collation elements, and the character set | ||
2906 | is single byte, the single byte character set that we | ||
2907 | build below suffices. */ | ||
2908 | if (nrules > 0 || dfa->mb_cur_max > 1) | ||
2909 | { | ||
2910 | /* Check the space of the arrays. */ | ||
2911 | if (BE (*range_alloc == mbcset->nranges, 0)) | ||
2912 | { | ||
2913 | /* There is not enough space, need realloc. */ | ||
2914 | uint32_t *new_array_start; | ||
2915 | uint32_t *new_array_end; | ||
2916 | Idx new_nranges; | ||
2917 | |||
2918 | /* +1 in case of mbcset->nranges is 0. */ | ||
2919 | new_nranges = 2 * mbcset->nranges + 1; | ||
2920 | new_array_start = re_realloc (mbcset->range_starts, uint32_t, | ||
2921 | new_nranges); | ||
2922 | new_array_end = re_realloc (mbcset->range_ends, uint32_t, | ||
2923 | new_nranges); | ||
2924 | |||
2925 | if (BE (new_array_start == NULL || new_array_end == NULL, 0)) | ||
2926 | return REG_ESPACE; | ||
2927 | |||
2928 | mbcset->range_starts = new_array_start; | ||
2929 | mbcset->range_ends = new_array_end; | ||
2930 | *range_alloc = new_nranges; | ||
2931 | } | ||
2932 | |||
2933 | mbcset->range_starts[mbcset->nranges] = start_collseq; | ||
2934 | mbcset->range_ends[mbcset->nranges++] = end_collseq; | ||
2935 | } | ||
2936 | |||
2937 | /* Build the table for single byte characters. */ | ||
2938 | for (ch = 0; ch < SBC_MAX; ch++) | ||
2939 | { | ||
2940 | uint32_t ch_collseq; | ||
2941 | /* | ||
2942 | if (MB_CUR_MAX == 1) | ||
2943 | */ | ||
2944 | if (nrules == 0) | ||
2945 | ch_collseq = collseqmb[ch]; | ||
2946 | else | ||
2947 | ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch)); | ||
2948 | if (start_collseq <= ch_collseq && ch_collseq <= end_collseq) | ||
2949 | bitset_set (sbcset, ch); | ||
2950 | } | ||
2951 | return REG_NOERROR; | ||
2952 | } | ||
2953 | |||
2954 | /* Local function for parse_bracket_exp used in _LIBC environement. | ||
2955 | Build the collating element which is represented by NAME. | ||
2956 | The result are written to MBCSET and SBCSET. | ||
2957 | COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a | ||
2958 | pointer argument sinse we may update it. */ | ||
2959 | |||
2960 | auto inline reg_errcode_t | ||
2961 | __attribute ((always_inline)) | ||
2962 | build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name) | ||
2963 | re_charset_t *mbcset; | ||
2964 | Idx *coll_sym_alloc; | ||
2965 | bitset_t sbcset; | ||
2966 | const unsigned char *name; | ||
2967 | { | ||
2968 | int32_t elem, idx; | ||
2969 | size_t name_len = strlen ((const char *) name); | ||
2970 | if (nrules != 0) | ||
2971 | { | ||
2972 | elem = seek_collating_symbol_entry (name, name_len); | ||
2973 | if (symb_table[2 * elem] != 0) | ||
2974 | { | ||
2975 | /* We found the entry. */ | ||
2976 | idx = symb_table[2 * elem + 1]; | ||
2977 | /* Skip the name of collating element name. */ | ||
2978 | idx += 1 + extra[idx]; | ||
2979 | } | ||
2980 | else if (symb_table[2 * elem] == 0 && name_len == 1) | ||
2981 | { | ||
2982 | /* No valid character, treat it as a normal | ||
2983 | character. */ | ||
2984 | bitset_set (sbcset, name[0]); | ||
2985 | return REG_NOERROR; | ||
2986 | } | ||
2987 | else | ||
2988 | return REG_ECOLLATE; | ||
2989 | |||
2990 | /* Got valid collation sequence, add it as a new entry. */ | ||
2991 | /* Check the space of the arrays. */ | ||
2992 | if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0)) | ||
2993 | { | ||
2994 | /* Not enough, realloc it. */ | ||
2995 | /* +1 in case of mbcset->ncoll_syms is 0. */ | ||
2996 | Idx new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1; | ||
2997 | /* Use realloc since mbcset->coll_syms is NULL | ||
2998 | if *alloc == 0. */ | ||
2999 | int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t, | ||
3000 | new_coll_sym_alloc); | ||
3001 | if (BE (new_coll_syms == NULL, 0)) | ||
3002 | return REG_ESPACE; | ||
3003 | mbcset->coll_syms = new_coll_syms; | ||
3004 | *coll_sym_alloc = new_coll_sym_alloc; | ||
3005 | } | ||
3006 | mbcset->coll_syms[mbcset->ncoll_syms++] = idx; | ||
3007 | return REG_NOERROR; | ||
3008 | } | ||
3009 | else | ||
3010 | { | ||
3011 | if (BE (name_len != 1, 0)) | ||
3012 | return REG_ECOLLATE; | ||
3013 | else | ||
3014 | { | ||
3015 | bitset_set (sbcset, name[0]); | ||
3016 | return REG_NOERROR; | ||
3017 | } | ||
3018 | } | ||
3019 | } | ||
3020 | #endif | ||
3021 | |||
3022 | re_token_t br_token; | ||
3023 | re_bitset_ptr_t sbcset; | ||
3024 | #ifdef RE_ENABLE_I18N | ||
3025 | re_charset_t *mbcset; | ||
3026 | Idx coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0; | ||
3027 | Idx equiv_class_alloc = 0, char_class_alloc = 0; | ||
3028 | #endif /* not RE_ENABLE_I18N */ | ||
3029 | bool non_match = false; | ||
3030 | bin_tree_t *work_tree; | ||
3031 | int token_len; | ||
3032 | bool first_round = true; | ||
3033 | #ifdef _LIBC | ||
3034 | collseqmb = (const unsigned char *) | ||
3035 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); | ||
3036 | nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); | ||
3037 | if (nrules) | ||
3038 | { | ||
3039 | /* | ||
3040 | if (MB_CUR_MAX > 1) | ||
3041 | */ | ||
3042 | collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); | ||
3043 | table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB); | ||
3044 | symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE, | ||
3045 | _NL_COLLATE_SYMB_TABLEMB); | ||
3046 | extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, | ||
3047 | _NL_COLLATE_SYMB_EXTRAMB); | ||
3048 | } | ||
3049 | #endif | ||
3050 | sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); | ||
3051 | #ifdef RE_ENABLE_I18N | ||
3052 | mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); | ||
3053 | #endif /* RE_ENABLE_I18N */ | ||
3054 | #ifdef RE_ENABLE_I18N | ||
3055 | if (BE (sbcset == NULL || mbcset == NULL, 0)) | ||
3056 | #else | ||
3057 | if (BE (sbcset == NULL, 0)) | ||
3058 | #endif /* RE_ENABLE_I18N */ | ||
3059 | { | ||
3060 | *err = REG_ESPACE; | ||
3061 | return NULL; | ||
3062 | } | ||
3063 | |||
3064 | token_len = peek_token_bracket (token, regexp, syntax); | ||
3065 | if (BE (token->type == END_OF_RE, 0)) | ||
3066 | { | ||
3067 | *err = REG_BADPAT; | ||
3068 | goto parse_bracket_exp_free_return; | ||
3069 | } | ||
3070 | if (token->type == OP_NON_MATCH_LIST) | ||
3071 | { | ||
3072 | #ifdef RE_ENABLE_I18N | ||
3073 | mbcset->non_match = 1; | ||
3074 | #endif /* not RE_ENABLE_I18N */ | ||
3075 | non_match = true; | ||
3076 | if (syntax & RE_HAT_LISTS_NOT_NEWLINE) | ||
3077 | bitset_set (sbcset, '\0'); | ||
3078 | re_string_skip_bytes (regexp, token_len); /* Skip a token. */ | ||
3079 | token_len = peek_token_bracket (token, regexp, syntax); | ||
3080 | if (BE (token->type == END_OF_RE, 0)) | ||
3081 | { | ||
3082 | *err = REG_BADPAT; | ||
3083 | goto parse_bracket_exp_free_return; | ||
3084 | } | ||
3085 | } | ||
3086 | |||
3087 | /* We treat the first ']' as a normal character. */ | ||
3088 | if (token->type == OP_CLOSE_BRACKET) | ||
3089 | token->type = CHARACTER; | ||
3090 | |||
3091 | while (1) | ||
3092 | { | ||
3093 | bracket_elem_t start_elem, end_elem; | ||
3094 | unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE]; | ||
3095 | unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE]; | ||
3096 | reg_errcode_t ret; | ||
3097 | int token_len2 = 0; | ||
3098 | bool is_range_exp = false; | ||
3099 | re_token_t token2; | ||
3100 | |||
3101 | start_elem.opr.name = start_name_buf; | ||
3102 | ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa, | ||
3103 | syntax, first_round); | ||
3104 | if (BE (ret != REG_NOERROR, 0)) | ||
3105 | { | ||
3106 | *err = ret; | ||
3107 | goto parse_bracket_exp_free_return; | ||
3108 | } | ||
3109 | first_round = false; | ||
3110 | |||
3111 | /* Get information about the next token. We need it in any case. */ | ||
3112 | token_len = peek_token_bracket (token, regexp, syntax); | ||
3113 | |||
3114 | /* Do not check for ranges if we know they are not allowed. */ | ||
3115 | if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS) | ||
3116 | { | ||
3117 | if (BE (token->type == END_OF_RE, 0)) | ||
3118 | { | ||
3119 | *err = REG_EBRACK; | ||
3120 | goto parse_bracket_exp_free_return; | ||
3121 | } | ||
3122 | if (token->type == OP_CHARSET_RANGE) | ||
3123 | { | ||
3124 | re_string_skip_bytes (regexp, token_len); /* Skip '-'. */ | ||
3125 | token_len2 = peek_token_bracket (&token2, regexp, syntax); | ||
3126 | if (BE (token2.type == END_OF_RE, 0)) | ||
3127 | { | ||
3128 | *err = REG_EBRACK; | ||
3129 | goto parse_bracket_exp_free_return; | ||
3130 | } | ||
3131 | if (token2.type == OP_CLOSE_BRACKET) | ||
3132 | { | ||
3133 | /* We treat the last '-' as a normal character. */ | ||
3134 | re_string_skip_bytes (regexp, -token_len); | ||
3135 | token->type = CHARACTER; | ||
3136 | } | ||
3137 | else | ||
3138 | is_range_exp = true; | ||
3139 | } | ||
3140 | } | ||
3141 | |||
3142 | if (is_range_exp == true) | ||
3143 | { | ||
3144 | end_elem.opr.name = end_name_buf; | ||
3145 | ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2, | ||
3146 | dfa, syntax, true); | ||
3147 | if (BE (ret != REG_NOERROR, 0)) | ||
3148 | { | ||
3149 | *err = ret; | ||
3150 | goto parse_bracket_exp_free_return; | ||
3151 | } | ||
3152 | |||
3153 | token_len = peek_token_bracket (token, regexp, syntax); | ||
3154 | |||
3155 | #ifdef _LIBC | ||
3156 | *err = build_range_exp (sbcset, mbcset, &range_alloc, | ||
3157 | &start_elem, &end_elem); | ||
3158 | #else | ||
3159 | # ifdef RE_ENABLE_I18N | ||
3160 | *err = build_range_exp (sbcset, | ||
3161 | dfa->mb_cur_max > 1 ? mbcset : NULL, | ||
3162 | &range_alloc, &start_elem, &end_elem); | ||
3163 | # else | ||
3164 | *err = build_range_exp (sbcset, &start_elem, &end_elem); | ||
3165 | # endif | ||
3166 | #endif /* RE_ENABLE_I18N */ | ||
3167 | if (BE (*err != REG_NOERROR, 0)) | ||
3168 | goto parse_bracket_exp_free_return; | ||
3169 | } | ||
3170 | else | ||
3171 | { | ||
3172 | switch (start_elem.type) | ||
3173 | { | ||
3174 | case SB_CHAR: | ||
3175 | bitset_set (sbcset, start_elem.opr.ch); | ||
3176 | break; | ||
3177 | #ifdef RE_ENABLE_I18N | ||
3178 | case MB_CHAR: | ||
3179 | /* Check whether the array has enough space. */ | ||
3180 | if (BE (mbchar_alloc == mbcset->nmbchars, 0)) | ||
3181 | { | ||
3182 | wchar_t *new_mbchars; | ||
3183 | /* Not enough, realloc it. */ | ||
3184 | /* +1 in case of mbcset->nmbchars is 0. */ | ||
3185 | mbchar_alloc = 2 * mbcset->nmbchars + 1; | ||
3186 | /* Use realloc since array is NULL if *alloc == 0. */ | ||
3187 | new_mbchars = re_realloc (mbcset->mbchars, wchar_t, | ||
3188 | mbchar_alloc); | ||
3189 | if (BE (new_mbchars == NULL, 0)) | ||
3190 | goto parse_bracket_exp_espace; | ||
3191 | mbcset->mbchars = new_mbchars; | ||
3192 | } | ||
3193 | mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch; | ||
3194 | break; | ||
3195 | #endif /* RE_ENABLE_I18N */ | ||
3196 | case EQUIV_CLASS: | ||
3197 | *err = build_equiv_class (sbcset, | ||
3198 | #ifdef RE_ENABLE_I18N | ||
3199 | mbcset, &equiv_class_alloc, | ||
3200 | #endif /* RE_ENABLE_I18N */ | ||
3201 | start_elem.opr.name); | ||
3202 | if (BE (*err != REG_NOERROR, 0)) | ||
3203 | goto parse_bracket_exp_free_return; | ||
3204 | break; | ||
3205 | case COLL_SYM: | ||
3206 | *err = build_collating_symbol (sbcset, | ||
3207 | #ifdef RE_ENABLE_I18N | ||
3208 | mbcset, &coll_sym_alloc, | ||
3209 | #endif /* RE_ENABLE_I18N */ | ||
3210 | start_elem.opr.name); | ||
3211 | if (BE (*err != REG_NOERROR, 0)) | ||
3212 | goto parse_bracket_exp_free_return; | ||
3213 | break; | ||
3214 | case CHAR_CLASS: | ||
3215 | *err = build_charclass (regexp->trans, sbcset, | ||
3216 | #ifdef RE_ENABLE_I18N | ||
3217 | mbcset, &char_class_alloc, | ||
3218 | #endif /* RE_ENABLE_I18N */ | ||
3219 | start_elem.opr.name, syntax); | ||
3220 | if (BE (*err != REG_NOERROR, 0)) | ||
3221 | goto parse_bracket_exp_free_return; | ||
3222 | break; | ||
3223 | default: | ||
3224 | assert (0); | ||
3225 | break; | ||
3226 | } | ||
3227 | } | ||
3228 | if (BE (token->type == END_OF_RE, 0)) | ||
3229 | { | ||
3230 | *err = REG_EBRACK; | ||
3231 | goto parse_bracket_exp_free_return; | ||
3232 | } | ||
3233 | if (token->type == OP_CLOSE_BRACKET) | ||
3234 | break; | ||
3235 | } | ||
3236 | |||
3237 | re_string_skip_bytes (regexp, token_len); /* Skip a token. */ | ||
3238 | |||
3239 | /* If it is non-matching list. */ | ||
3240 | if (non_match) | ||
3241 | bitset_not (sbcset); | ||
3242 | |||
3243 | #ifdef RE_ENABLE_I18N | ||
3244 | /* Ensure only single byte characters are set. */ | ||
3245 | if (dfa->mb_cur_max > 1) | ||
3246 | bitset_mask (sbcset, dfa->sb_char); | ||
3247 | |||
3248 | if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes | ||
3249 | || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes | ||
3250 | || mbcset->non_match))) | ||
3251 | { | ||
3252 | bin_tree_t *mbc_tree; | ||
3253 | int sbc_idx; | ||
3254 | /* Build a tree for complex bracket. */ | ||
3255 | dfa->has_mb_node = 1; | ||
3256 | br_token.type = COMPLEX_BRACKET; | ||
3257 | br_token.opr.mbcset = mbcset; | ||
3258 | mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token); | ||
3259 | if (BE (mbc_tree == NULL, 0)) | ||
3260 | goto parse_bracket_exp_espace; | ||
3261 | for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx) | ||
3262 | if (sbcset[sbc_idx]) | ||
3263 | break; | ||
3264 | /* If there are no bits set in sbcset, there is no point | ||
3265 | of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */ | ||
3266 | if (sbc_idx < BITSET_WORDS) | ||
3267 | { | ||
3268 | /* Build a tree for simple bracket. */ | ||
3269 | br_token.type = SIMPLE_BRACKET; | ||
3270 | br_token.opr.sbcset = sbcset; | ||
3271 | work_tree = create_token_tree (dfa, NULL, NULL, &br_token); | ||
3272 | if (BE (work_tree == NULL, 0)) | ||
3273 | goto parse_bracket_exp_espace; | ||
3274 | |||
3275 | /* Then join them by ALT node. */ | ||
3276 | work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT); | ||
3277 | if (BE (work_tree == NULL, 0)) | ||
3278 | goto parse_bracket_exp_espace; | ||
3279 | } | ||
3280 | else | ||
3281 | { | ||
3282 | re_free (sbcset); | ||
3283 | work_tree = mbc_tree; | ||
3284 | } | ||
3285 | } | ||
3286 | else | ||
3287 | #endif /* not RE_ENABLE_I18N */ | ||
3288 | { | ||
3289 | #ifdef RE_ENABLE_I18N | ||
3290 | free_charset (mbcset); | ||
3291 | #endif | ||
3292 | /* Build a tree for simple bracket. */ | ||
3293 | br_token.type = SIMPLE_BRACKET; | ||
3294 | br_token.opr.sbcset = sbcset; | ||
3295 | work_tree = create_token_tree (dfa, NULL, NULL, &br_token); | ||
3296 | if (BE (work_tree == NULL, 0)) | ||
3297 | goto parse_bracket_exp_espace; | ||
3298 | } | ||
3299 | return work_tree; | ||
3300 | |||
3301 | parse_bracket_exp_espace: | ||
3302 | *err = REG_ESPACE; | ||
3303 | parse_bracket_exp_free_return: | ||
3304 | re_free (sbcset); | ||
3305 | #ifdef RE_ENABLE_I18N | ||
3306 | free_charset (mbcset); | ||
3307 | #endif /* RE_ENABLE_I18N */ | ||
3308 | return NULL; | ||
3309 | } | ||
3310 | |||
3311 | /* Parse an element in the bracket expression. */ | ||
3312 | |||
3313 | static reg_errcode_t | ||
3314 | parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp, | ||
3315 | re_token_t *token, int token_len, re_dfa_t *dfa, | ||
3316 | reg_syntax_t syntax, bool accept_hyphen) | ||
3317 | { | ||
3318 | #ifdef RE_ENABLE_I18N | ||
3319 | int cur_char_size; | ||
3320 | cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp)); | ||
3321 | if (cur_char_size > 1) | ||
3322 | { | ||
3323 | elem->type = MB_CHAR; | ||
3324 | elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp)); | ||
3325 | re_string_skip_bytes (regexp, cur_char_size); | ||
3326 | return REG_NOERROR; | ||
3327 | } | ||
3328 | #endif /* RE_ENABLE_I18N */ | ||
3329 | re_string_skip_bytes (regexp, token_len); /* Skip a token. */ | ||
3330 | if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS | ||
3331 | || token->type == OP_OPEN_EQUIV_CLASS) | ||
3332 | return parse_bracket_symbol (elem, regexp, token); | ||
3333 | if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen) | ||
3334 | { | ||
3335 | /* A '-' must only appear as anything but a range indicator before | ||
3336 | the closing bracket. Everything else is an error. */ | ||
3337 | re_token_t token2; | ||
3338 | (void) peek_token_bracket (&token2, regexp, syntax); | ||
3339 | if (token2.type != OP_CLOSE_BRACKET) | ||
3340 | /* The actual error value is not standardized since this whole | ||
3341 | case is undefined. But ERANGE makes good sense. */ | ||
3342 | return REG_ERANGE; | ||
3343 | } | ||
3344 | elem->type = SB_CHAR; | ||
3345 | elem->opr.ch = token->opr.c; | ||
3346 | return REG_NOERROR; | ||
3347 | } | ||
3348 | |||
3349 | /* Parse a bracket symbol in the bracket expression. Bracket symbols are | ||
3350 | such as [:<character_class>:], [.<collating_element>.], and | ||
3351 | [=<equivalent_class>=]. */ | ||
3352 | |||
3353 | static reg_errcode_t | ||
3354 | parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp, | ||
3355 | re_token_t *token) | ||
3356 | { | ||
3357 | unsigned char ch, delim = token->opr.c; | ||
3358 | int i = 0; | ||
3359 | if (re_string_eoi(regexp)) | ||
3360 | return REG_EBRACK; | ||
3361 | for (;; ++i) | ||
3362 | { | ||
3363 | if (i >= BRACKET_NAME_BUF_SIZE) | ||
3364 | return REG_EBRACK; | ||
3365 | if (token->type == OP_OPEN_CHAR_CLASS) | ||
3366 | ch = re_string_fetch_byte_case (regexp); | ||
3367 | else | ||
3368 | ch = re_string_fetch_byte (regexp); | ||
3369 | if (re_string_eoi(regexp)) | ||
3370 | return REG_EBRACK; | ||
3371 | if (ch == delim && re_string_peek_byte (regexp, 0) == ']') | ||
3372 | break; | ||
3373 | elem->opr.name[i] = ch; | ||
3374 | } | ||
3375 | re_string_skip_bytes (regexp, 1); | ||
3376 | elem->opr.name[i] = '\0'; | ||
3377 | switch (token->type) | ||
3378 | { | ||
3379 | case OP_OPEN_COLL_ELEM: | ||
3380 | elem->type = COLL_SYM; | ||
3381 | break; | ||
3382 | case OP_OPEN_EQUIV_CLASS: | ||
3383 | elem->type = EQUIV_CLASS; | ||
3384 | break; | ||
3385 | case OP_OPEN_CHAR_CLASS: | ||
3386 | elem->type = CHAR_CLASS; | ||
3387 | break; | ||
3388 | default: | ||
3389 | break; | ||
3390 | } | ||
3391 | return REG_NOERROR; | ||
3392 | } | ||
3393 | |||
3394 | /* Helper function for parse_bracket_exp. | ||
3395 | Build the equivalence class which is represented by NAME. | ||
3396 | The result are written to MBCSET and SBCSET. | ||
3397 | EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes, | ||
3398 | is a pointer argument sinse we may update it. */ | ||
3399 | |||
3400 | static reg_errcode_t | ||
3401 | #ifdef RE_ENABLE_I18N | ||
3402 | build_equiv_class (bitset_t sbcset, re_charset_t *mbcset, | ||
3403 | Idx *equiv_class_alloc, const unsigned char *name) | ||
3404 | #else /* not RE_ENABLE_I18N */ | ||
3405 | build_equiv_class (bitset_t sbcset, const unsigned char *name) | ||
3406 | #endif /* not RE_ENABLE_I18N */ | ||
3407 | { | ||
3408 | #ifdef _LIBC | ||
3409 | uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); | ||
3410 | if (nrules != 0) | ||
3411 | { | ||
3412 | const int32_t *table, *indirect; | ||
3413 | const unsigned char *weights, *extra, *cp; | ||
3414 | unsigned char char_buf[2]; | ||
3415 | int32_t idx1, idx2; | ||
3416 | unsigned int ch; | ||
3417 | size_t len; | ||
3418 | /* This #include defines a local function! */ | ||
3419 | # include <locale/weight.h> | ||
3420 | /* Calculate the index for equivalence class. */ | ||
3421 | cp = name; | ||
3422 | table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); | ||
3423 | weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE, | ||
3424 | _NL_COLLATE_WEIGHTMB); | ||
3425 | extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, | ||
3426 | _NL_COLLATE_EXTRAMB); | ||
3427 | indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, | ||
3428 | _NL_COLLATE_INDIRECTMB); | ||
3429 | idx1 = findidx (&cp); | ||
3430 | if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0)) | ||
3431 | /* This isn't a valid character. */ | ||
3432 | return REG_ECOLLATE; | ||
3433 | |||
3434 | /* Build single byte matcing table for this equivalence class. */ | ||
3435 | char_buf[1] = (unsigned char) '\0'; | ||
3436 | len = weights[idx1]; | ||
3437 | for (ch = 0; ch < SBC_MAX; ++ch) | ||
3438 | { | ||
3439 | char_buf[0] = ch; | ||
3440 | cp = char_buf; | ||
3441 | idx2 = findidx (&cp); | ||
3442 | /* | ||
3443 | idx2 = table[ch]; | ||
3444 | */ | ||
3445 | if (idx2 == 0) | ||
3446 | /* This isn't a valid character. */ | ||
3447 | continue; | ||
3448 | if (len == weights[idx2]) | ||
3449 | { | ||
3450 | int cnt = 0; | ||
3451 | while (cnt <= len && | ||
3452 | weights[idx1 + 1 + cnt] == weights[idx2 + 1 + cnt]) | ||
3453 | ++cnt; | ||
3454 | |||
3455 | if (cnt > len) | ||
3456 | bitset_set (sbcset, ch); | ||
3457 | } | ||
3458 | } | ||
3459 | /* Check whether the array has enough space. */ | ||
3460 | if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0)) | ||
3461 | { | ||
3462 | /* Not enough, realloc it. */ | ||
3463 | /* +1 in case of mbcset->nequiv_classes is 0. */ | ||
3464 | Idx new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1; | ||
3465 | /* Use realloc since the array is NULL if *alloc == 0. */ | ||
3466 | int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes, | ||
3467 | int32_t, | ||
3468 | new_equiv_class_alloc); | ||
3469 | if (BE (new_equiv_classes == NULL, 0)) | ||
3470 | return REG_ESPACE; | ||
3471 | mbcset->equiv_classes = new_equiv_classes; | ||
3472 | *equiv_class_alloc = new_equiv_class_alloc; | ||
3473 | } | ||
3474 | mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1; | ||
3475 | } | ||
3476 | else | ||
3477 | #endif /* _LIBC */ | ||
3478 | { | ||
3479 | if (BE (strlen ((const char *) name) != 1, 0)) | ||
3480 | return REG_ECOLLATE; | ||
3481 | bitset_set (sbcset, *name); | ||
3482 | } | ||
3483 | return REG_NOERROR; | ||
3484 | } | ||
3485 | |||
3486 | /* Helper function for parse_bracket_exp. | ||
3487 | Build the character class which is represented by NAME. | ||
3488 | The result are written to MBCSET and SBCSET. | ||
3489 | CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes, | ||
3490 | is a pointer argument sinse we may update it. */ | ||
3491 | |||
3492 | static reg_errcode_t | ||
3493 | #ifdef RE_ENABLE_I18N | ||
3494 | build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, | ||
3495 | re_charset_t *mbcset, Idx *char_class_alloc, | ||
3496 | const unsigned char *class_name, reg_syntax_t syntax) | ||
3497 | #else /* not RE_ENABLE_I18N */ | ||
3498 | build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, | ||
3499 | const unsigned char *class_name, reg_syntax_t syntax) | ||
3500 | #endif /* not RE_ENABLE_I18N */ | ||
3501 | { | ||
3502 | int i; | ||
3503 | const char *name = (const char *) class_name; | ||
3504 | |||
3505 | /* In case of REG_ICASE "upper" and "lower" match the both of | ||
3506 | upper and lower cases. */ | ||
3507 | if ((syntax & RE_ICASE) | ||
3508 | && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0)) | ||
3509 | name = "alpha"; | ||
3510 | |||
3511 | #ifdef RE_ENABLE_I18N | ||
3512 | /* Check the space of the arrays. */ | ||
3513 | if (BE (*char_class_alloc == mbcset->nchar_classes, 0)) | ||
3514 | { | ||
3515 | /* Not enough, realloc it. */ | ||
3516 | /* +1 in case of mbcset->nchar_classes is 0. */ | ||
3517 | Idx new_char_class_alloc = 2 * mbcset->nchar_classes + 1; | ||
3518 | /* Use realloc since array is NULL if *alloc == 0. */ | ||
3519 | wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t, | ||
3520 | new_char_class_alloc); | ||
3521 | if (BE (new_char_classes == NULL, 0)) | ||
3522 | return REG_ESPACE; | ||
3523 | mbcset->char_classes = new_char_classes; | ||
3524 | *char_class_alloc = new_char_class_alloc; | ||
3525 | } | ||
3526 | mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name); | ||
3527 | #endif /* RE_ENABLE_I18N */ | ||
3528 | |||
3529 | #define BUILD_CHARCLASS_LOOP(ctype_func) \ | ||
3530 | do { \ | ||
3531 | if (BE (trans != NULL, 0)) \ | ||
3532 | { \ | ||
3533 | for (i = 0; i < SBC_MAX; ++i) \ | ||
3534 | if (ctype_func (i)) \ | ||
3535 | bitset_set (sbcset, trans[i]); \ | ||
3536 | } \ | ||
3537 | else \ | ||
3538 | { \ | ||
3539 | for (i = 0; i < SBC_MAX; ++i) \ | ||
3540 | if (ctype_func (i)) \ | ||
3541 | bitset_set (sbcset, i); \ | ||
3542 | } \ | ||
3543 | } while (0) | ||
3544 | |||
3545 | if (strcmp (name, "alnum") == 0) | ||
3546 | BUILD_CHARCLASS_LOOP (isalnum); | ||
3547 | else if (strcmp (name, "cntrl") == 0) | ||
3548 | BUILD_CHARCLASS_LOOP (iscntrl); | ||
3549 | else if (strcmp (name, "lower") == 0) | ||
3550 | BUILD_CHARCLASS_LOOP (islower); | ||
3551 | else if (strcmp (name, "space") == 0) | ||
3552 | BUILD_CHARCLASS_LOOP (isspace); | ||
3553 | else if (strcmp (name, "alpha") == 0) | ||
3554 | BUILD_CHARCLASS_LOOP (isalpha); | ||
3555 | else if (strcmp (name, "digit") == 0) | ||
3556 | BUILD_CHARCLASS_LOOP (isdigit); | ||
3557 | else if (strcmp (name, "print") == 0) | ||
3558 | BUILD_CHARCLASS_LOOP (isprint); | ||
3559 | else if (strcmp (name, "upper") == 0) | ||
3560 | BUILD_CHARCLASS_LOOP (isupper); | ||
3561 | else if (strcmp (name, "blank") == 0) | ||
3562 | BUILD_CHARCLASS_LOOP (isblank); | ||
3563 | else if (strcmp (name, "graph") == 0) | ||
3564 | BUILD_CHARCLASS_LOOP (isgraph); | ||
3565 | else if (strcmp (name, "punct") == 0) | ||
3566 | BUILD_CHARCLASS_LOOP (ispunct); | ||
3567 | else if (strcmp (name, "xdigit") == 0) | ||
3568 | BUILD_CHARCLASS_LOOP (isxdigit); | ||
3569 | else | ||
3570 | return REG_ECTYPE; | ||
3571 | |||
3572 | return REG_NOERROR; | ||
3573 | } | ||
3574 | |||
3575 | static bin_tree_t * | ||
3576 | build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, | ||
3577 | const unsigned char *class_name, | ||
3578 | const unsigned char *extra, bool non_match, | ||
3579 | reg_errcode_t *err) | ||
3580 | { | ||
3581 | re_bitset_ptr_t sbcset; | ||
3582 | #ifdef RE_ENABLE_I18N | ||
3583 | re_charset_t *mbcset; | ||
3584 | Idx alloc = 0; | ||
3585 | #endif /* not RE_ENABLE_I18N */ | ||
3586 | reg_errcode_t ret; | ||
3587 | re_token_t br_token; | ||
3588 | bin_tree_t *tree; | ||
3589 | |||
3590 | sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); | ||
3591 | #ifdef RE_ENABLE_I18N | ||
3592 | mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); | ||
3593 | #endif /* RE_ENABLE_I18N */ | ||
3594 | |||
3595 | #ifdef RE_ENABLE_I18N | ||
3596 | if (BE (sbcset == NULL || mbcset == NULL, 0)) | ||
3597 | #else /* not RE_ENABLE_I18N */ | ||
3598 | if (BE (sbcset == NULL, 0)) | ||
3599 | #endif /* not RE_ENABLE_I18N */ | ||
3600 | { | ||
3601 | *err = REG_ESPACE; | ||
3602 | return NULL; | ||
3603 | } | ||
3604 | |||
3605 | if (non_match) | ||
3606 | { | ||
3607 | #ifdef RE_ENABLE_I18N | ||
3608 | /* | ||
3609 | if (syntax & RE_HAT_LISTS_NOT_NEWLINE) | ||
3610 | bitset_set(cset->sbcset, '\0'); | ||
3611 | */ | ||
3612 | mbcset->non_match = 1; | ||
3613 | #endif /* not RE_ENABLE_I18N */ | ||
3614 | } | ||
3615 | |||
3616 | /* We don't care the syntax in this case. */ | ||
3617 | ret = build_charclass (trans, sbcset, | ||
3618 | #ifdef RE_ENABLE_I18N | ||
3619 | mbcset, &alloc, | ||
3620 | #endif /* RE_ENABLE_I18N */ | ||
3621 | class_name, 0); | ||
3622 | |||
3623 | if (BE (ret != REG_NOERROR, 0)) | ||
3624 | { | ||
3625 | re_free (sbcset); | ||
3626 | #ifdef RE_ENABLE_I18N | ||
3627 | free_charset (mbcset); | ||
3628 | #endif /* RE_ENABLE_I18N */ | ||
3629 | *err = ret; | ||
3630 | return NULL; | ||
3631 | } | ||
3632 | /* \w match '_' also. */ | ||
3633 | for (; *extra; extra++) | ||
3634 | bitset_set (sbcset, *extra); | ||
3635 | |||
3636 | /* If it is non-matching list. */ | ||
3637 | if (non_match) | ||
3638 | bitset_not (sbcset); | ||
3639 | |||
3640 | #ifdef RE_ENABLE_I18N | ||
3641 | /* Ensure only single byte characters are set. */ | ||
3642 | if (dfa->mb_cur_max > 1) | ||
3643 | bitset_mask (sbcset, dfa->sb_char); | ||
3644 | #endif | ||
3645 | |||
3646 | /* Build a tree for simple bracket. */ | ||
3647 | br_token.type = SIMPLE_BRACKET; | ||
3648 | br_token.opr.sbcset = sbcset; | ||
3649 | tree = create_token_tree (dfa, NULL, NULL, &br_token); | ||
3650 | if (BE (tree == NULL, 0)) | ||
3651 | goto build_word_op_espace; | ||
3652 | |||
3653 | #ifdef RE_ENABLE_I18N | ||
3654 | if (dfa->mb_cur_max > 1) | ||
3655 | { | ||
3656 | bin_tree_t *mbc_tree; | ||
3657 | /* Build a tree for complex bracket. */ | ||
3658 | br_token.type = COMPLEX_BRACKET; | ||
3659 | br_token.opr.mbcset = mbcset; | ||
3660 | dfa->has_mb_node = 1; | ||
3661 | mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token); | ||
3662 | if (BE (mbc_tree == NULL, 0)) | ||
3663 | goto build_word_op_espace; | ||
3664 | /* Then join them by ALT node. */ | ||
3665 | tree = create_tree (dfa, tree, mbc_tree, OP_ALT); | ||
3666 | if (BE (mbc_tree != NULL, 1)) | ||
3667 | return tree; | ||
3668 | } | ||
3669 | else | ||
3670 | { | ||
3671 | free_charset (mbcset); | ||
3672 | return tree; | ||
3673 | } | ||
3674 | #else /* not RE_ENABLE_I18N */ | ||
3675 | return tree; | ||
3676 | #endif /* not RE_ENABLE_I18N */ | ||
3677 | |||
3678 | build_word_op_espace: | ||
3679 | re_free (sbcset); | ||
3680 | #ifdef RE_ENABLE_I18N | ||
3681 | free_charset (mbcset); | ||
3682 | #endif /* RE_ENABLE_I18N */ | ||
3683 | *err = REG_ESPACE; | ||
3684 | return NULL; | ||
3685 | } | ||
3686 | |||
3687 | /* This is intended for the expressions like "a{1,3}". | ||
3688 | Fetch a number from `input', and return the number. | ||
3689 | Return REG_MISSING if the number field is empty like "{,1}". | ||
3690 | Return REG_ERROR if an error occurred. */ | ||
3691 | |||
3692 | static Idx | ||
3693 | fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax) | ||
3694 | { | ||
3695 | Idx num = REG_MISSING; | ||
3696 | unsigned char c; | ||
3697 | while (1) | ||
3698 | { | ||
3699 | fetch_token (token, input, syntax); | ||
3700 | c = token->opr.c; | ||
3701 | if (BE (token->type == END_OF_RE, 0)) | ||
3702 | return REG_ERROR; | ||
3703 | if (token->type == OP_CLOSE_DUP_NUM || c == ',') | ||
3704 | break; | ||
3705 | num = ((token->type != CHARACTER || c < '0' || '9' < c | ||
3706 | || num == REG_ERROR) | ||
3707 | ? REG_ERROR | ||
3708 | : ((num == REG_MISSING) ? c - '0' : num * 10 + c - '0')); | ||
3709 | num = (num > RE_DUP_MAX) ? REG_ERROR : num; | ||
3710 | } | ||
3711 | return num; | ||
3712 | } | ||
3713 | |||
3714 | #ifdef RE_ENABLE_I18N | ||
3715 | static void | ||
3716 | free_charset (re_charset_t *cset) | ||
3717 | { | ||
3718 | re_free (cset->mbchars); | ||
3719 | # ifdef _LIBC | ||
3720 | re_free (cset->coll_syms); | ||
3721 | re_free (cset->equiv_classes); | ||
3722 | re_free (cset->range_starts); | ||
3723 | re_free (cset->range_ends); | ||
3724 | # endif | ||
3725 | re_free (cset->char_classes); | ||
3726 | re_free (cset); | ||
3727 | } | ||
3728 | #endif /* RE_ENABLE_I18N */ | ||
3729 | |||
3730 | /* Functions for binary tree operation. */ | ||
3731 | |||
3732 | /* Create a tree node. */ | ||
3733 | |||
3734 | static bin_tree_t * | ||
3735 | create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, | ||
3736 | re_token_type_t type) | ||
3737 | { | ||
3738 | re_token_t t; | ||
3739 | t.type = type; | ||
3740 | return create_token_tree (dfa, left, right, &t); | ||
3741 | } | ||
3742 | |||
3743 | static bin_tree_t * | ||
3744 | create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, | ||
3745 | const re_token_t *token) | ||
3746 | { | ||
3747 | bin_tree_t *tree; | ||
3748 | if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0)) | ||
3749 | { | ||
3750 | bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1); | ||
3751 | |||
3752 | if (storage == NULL) | ||
3753 | return NULL; | ||
3754 | storage->next = dfa->str_tree_storage; | ||
3755 | dfa->str_tree_storage = storage; | ||
3756 | dfa->str_tree_storage_idx = 0; | ||
3757 | } | ||
3758 | tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++]; | ||
3759 | |||
3760 | tree->parent = NULL; | ||
3761 | tree->left = left; | ||
3762 | tree->right = right; | ||
3763 | tree->token = *token; | ||
3764 | tree->token.duplicated = 0; | ||
3765 | tree->token.opt_subexp = 0; | ||
3766 | tree->first = NULL; | ||
3767 | tree->next = NULL; | ||
3768 | tree->node_idx = REG_MISSING; | ||
3769 | |||
3770 | if (left != NULL) | ||
3771 | left->parent = tree; | ||
3772 | if (right != NULL) | ||
3773 | right->parent = tree; | ||
3774 | return tree; | ||
3775 | } | ||
3776 | |||
3777 | /* Mark the tree SRC as an optional subexpression. | ||
3778 | To be called from preorder or postorder. */ | ||
3779 | |||
3780 | static reg_errcode_t | ||
3781 | mark_opt_subexp (void *extra, bin_tree_t *node) | ||
3782 | { | ||
3783 | Idx idx = (Idx) (long) extra; | ||
3784 | if (node->token.type == SUBEXP && node->token.opr.idx == idx) | ||
3785 | node->token.opt_subexp = 1; | ||
3786 | |||
3787 | return REG_NOERROR; | ||
3788 | } | ||
3789 | |||
3790 | /* Free the allocated memory inside NODE. */ | ||
3791 | |||
3792 | static void | ||
3793 | free_token (re_token_t *node) | ||
3794 | { | ||
3795 | #ifdef RE_ENABLE_I18N | ||
3796 | if (node->type == COMPLEX_BRACKET && node->duplicated == 0) | ||
3797 | free_charset (node->opr.mbcset); | ||
3798 | else | ||
3799 | #endif /* RE_ENABLE_I18N */ | ||
3800 | if (node->type == SIMPLE_BRACKET && node->duplicated == 0) | ||
3801 | re_free (node->opr.sbcset); | ||
3802 | } | ||
3803 | |||
3804 | /* Worker function for tree walking. Free the allocated memory inside NODE | ||
3805 | and its children. */ | ||
3806 | |||
3807 | static reg_errcode_t | ||
3808 | free_tree (void *extra, bin_tree_t *node) | ||
3809 | { | ||
3810 | free_token (&node->token); | ||
3811 | return REG_NOERROR; | ||
3812 | } | ||
3813 | |||
3814 | |||
3815 | /* Duplicate the node SRC, and return new node. This is a preorder | ||
3816 | visit similar to the one implemented by the generic visitor, but | ||
3817 | we need more infrastructure to maintain two parallel trees --- so, | ||
3818 | it's easier to duplicate. */ | ||
3819 | |||
3820 | static bin_tree_t * | ||
3821 | duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa) | ||
3822 | { | ||
3823 | const bin_tree_t *node; | ||
3824 | bin_tree_t *dup_root; | ||
3825 | bin_tree_t **p_new = &dup_root, *dup_node = root->parent; | ||
3826 | |||
3827 | for (node = root; ; ) | ||
3828 | { | ||
3829 | /* Create a new tree and link it back to the current parent. */ | ||
3830 | *p_new = create_token_tree (dfa, NULL, NULL, &node->token); | ||
3831 | if (*p_new == NULL) | ||
3832 | return NULL; | ||
3833 | (*p_new)->parent = dup_node; | ||
3834 | (*p_new)->token.duplicated = 1; | ||
3835 | dup_node = *p_new; | ||
3836 | |||
3837 | /* Go to the left node, or up and to the right. */ | ||
3838 | if (node->left) | ||
3839 | { | ||
3840 | node = node->left; | ||
3841 | p_new = &dup_node->left; | ||
3842 | } | ||
3843 | else | ||
3844 | { | ||
3845 | const bin_tree_t *prev = NULL; | ||
3846 | while (node->right == prev || node->right == NULL) | ||
3847 | { | ||
3848 | prev = node; | ||
3849 | node = node->parent; | ||
3850 | dup_node = dup_node->parent; | ||
3851 | if (!node) | ||
3852 | return dup_root; | ||
3853 | } | ||
3854 | node = node->right; | ||
3855 | p_new = &dup_node->right; | ||
3856 | } | ||
3857 | } | ||
3858 | } | ||
diff --git a/gl/regex.c b/gl/regex.c new file mode 100644 index 00000000..d4eb726b --- /dev/null +++ b/gl/regex.c | |||
@@ -0,0 +1,71 @@ | |||
1 | /* Extended regular expression matching and search library. | ||
2 | Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc. | ||
3 | This file is part of the GNU C Library. | ||
4 | Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License along | ||
17 | with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | /* Make sure noone compiles this code with a C++ compiler. */ | ||
23 | #if defined __cplusplus && defined _LIBC | ||
24 | # error "This is C code, use a C compiler" | ||
25 | #endif | ||
26 | |||
27 | #ifdef _LIBC | ||
28 | /* We have to keep the namespace clean. */ | ||
29 | # define regfree(preg) __regfree (preg) | ||
30 | # define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) | ||
31 | # define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) | ||
32 | # define regerror(errcode, preg, errbuf, errbuf_size) \ | ||
33 | __regerror(errcode, preg, errbuf, errbuf_size) | ||
34 | # define re_set_registers(bu, re, nu, st, en) \ | ||
35 | __re_set_registers (bu, re, nu, st, en) | ||
36 | # define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ | ||
37 | __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) | ||
38 | # define re_match(bufp, string, size, pos, regs) \ | ||
39 | __re_match (bufp, string, size, pos, regs) | ||
40 | # define re_search(bufp, string, size, startpos, range, regs) \ | ||
41 | __re_search (bufp, string, size, startpos, range, regs) | ||
42 | # define re_compile_pattern(pattern, length, bufp) \ | ||
43 | __re_compile_pattern (pattern, length, bufp) | ||
44 | # define re_set_syntax(syntax) __re_set_syntax (syntax) | ||
45 | # define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ | ||
46 | __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) | ||
47 | # define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) | ||
48 | |||
49 | # include "../locale/localeinfo.h" | ||
50 | #endif | ||
51 | |||
52 | /* On some systems, limits.h sets RE_DUP_MAX to a lower value than | ||
53 | GNU regex allows. Include it before <regex.h>, which correctly | ||
54 | #undefs RE_DUP_MAX and sets it to the right value. */ | ||
55 | #include <limits.h> | ||
56 | |||
57 | #include <regex.h> | ||
58 | #include "regex_internal.h" | ||
59 | |||
60 | #include "regex_internal.c" | ||
61 | #include "regcomp.c" | ||
62 | #include "regexec.c" | ||
63 | |||
64 | /* Binary backward compatibility. */ | ||
65 | #if _LIBC | ||
66 | # include <shlib-compat.h> | ||
67 | # if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3) | ||
68 | link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.") | ||
69 | int re_max_failures = 2000; | ||
70 | # endif | ||
71 | #endif | ||
diff --git a/gl/regex.h b/gl/regex.h new file mode 100644 index 00000000..6885ebdf --- /dev/null +++ b/gl/regex.h | |||
@@ -0,0 +1,671 @@ | |||
1 | /* Definitions for data structures and routines for the regular | ||
2 | expression library. | ||
3 | Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005,2006 | ||
4 | Free Software Foundation, Inc. | ||
5 | This file is part of the GNU C Library. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License along | ||
18 | with this program; if not, write to the Free Software Foundation, | ||
19 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
20 | |||
21 | #ifndef _REGEX_H | ||
22 | #define _REGEX_H 1 | ||
23 | |||
24 | #include <sys/types.h> | ||
25 | |||
26 | /* Allow the use in C++ code. */ | ||
27 | #ifdef __cplusplus | ||
28 | extern "C" { | ||
29 | #endif | ||
30 | |||
31 | /* Define __USE_GNU_REGEX to declare GNU extensions that violate the | ||
32 | POSIX name space rules. */ | ||
33 | #undef __USE_GNU_REGEX | ||
34 | #if (defined _GNU_SOURCE \ | ||
35 | || (!defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE \ | ||
36 | && !defined _XOPEN_SOURCE)) | ||
37 | # define __USE_GNU_REGEX 1 | ||
38 | #endif | ||
39 | |||
40 | #ifdef _REGEX_LARGE_OFFSETS | ||
41 | |||
42 | /* Use types and values that are wide enough to represent signed and | ||
43 | unsigned byte offsets in memory. This currently works only when | ||
44 | the regex code is used outside of the GNU C library; it is not yet | ||
45 | supported within glibc itself, and glibc users should not define | ||
46 | _REGEX_LARGE_OFFSETS. */ | ||
47 | |||
48 | /* The type of the offset of a byte within a string. | ||
49 | For historical reasons POSIX 1003.1-2004 requires that regoff_t be | ||
50 | at least as wide as off_t. However, many common POSIX platforms set | ||
51 | regoff_t to the more-sensible ssize_t and the Open Group has | ||
52 | signalled its intention to change the requirement to be that | ||
53 | regoff_t be at least as wide as ptrdiff_t and ssize_t; see XBD ERN | ||
54 | 60 (2005-08-25). We don't know of any hosts where ssize_t or | ||
55 | ptrdiff_t is wider than ssize_t, so ssize_t is safe. */ | ||
56 | typedef ssize_t regoff_t; | ||
57 | |||
58 | /* The type of nonnegative object indexes. Traditionally, GNU regex | ||
59 | uses 'int' for these. Code that uses __re_idx_t should work | ||
60 | regardless of whether the type is signed. */ | ||
61 | typedef size_t __re_idx_t; | ||
62 | |||
63 | /* The type of object sizes. */ | ||
64 | typedef size_t __re_size_t; | ||
65 | |||
66 | /* The type of object sizes, in places where the traditional code | ||
67 | uses unsigned long int. */ | ||
68 | typedef size_t __re_long_size_t; | ||
69 | |||
70 | #else | ||
71 | |||
72 | /* Use types that are binary-compatible with the traditional GNU regex | ||
73 | implementation, which mishandles strings longer than INT_MAX. */ | ||
74 | |||
75 | typedef int regoff_t; | ||
76 | typedef int __re_idx_t; | ||
77 | typedef unsigned int __re_size_t; | ||
78 | typedef unsigned long int __re_long_size_t; | ||
79 | |||
80 | #endif | ||
81 | |||
82 | /* The following two types have to be signed and unsigned integer type | ||
83 | wide enough to hold a value of a pointer. For most ANSI compilers | ||
84 | ptrdiff_t and size_t should be likely OK. Still size of these two | ||
85 | types is 2 for Microsoft C. Ugh... */ | ||
86 | typedef long int s_reg_t; | ||
87 | typedef unsigned long int active_reg_t; | ||
88 | |||
89 | /* The following bits are used to determine the regexp syntax we | ||
90 | recognize. The set/not-set meanings are chosen so that Emacs syntax | ||
91 | remains the value 0. The bits are given in alphabetical order, and | ||
92 | the definitions shifted by one from the previous bit; thus, when we | ||
93 | add or remove a bit, only one other definition need change. */ | ||
94 | typedef unsigned long int reg_syntax_t; | ||
95 | |||
96 | #ifdef __USE_GNU_REGEX | ||
97 | |||
98 | /* If this bit is not set, then \ inside a bracket expression is literal. | ||
99 | If set, then such a \ quotes the following character. */ | ||
100 | # define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) | ||
101 | |||
102 | /* If this bit is not set, then + and ? are operators, and \+ and \? are | ||
103 | literals. | ||
104 | If set, then \+ and \? are operators and + and ? are literals. */ | ||
105 | # define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) | ||
106 | |||
107 | /* If this bit is set, then character classes are supported. They are: | ||
108 | [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], | ||
109 | [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. | ||
110 | If not set, then character classes are not supported. */ | ||
111 | # define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) | ||
112 | |||
113 | /* If this bit is set, then ^ and $ are always anchors (outside bracket | ||
114 | expressions, of course). | ||
115 | If this bit is not set, then it depends: | ||
116 | ^ is an anchor if it is at the beginning of a regular | ||
117 | expression or after an open-group or an alternation operator; | ||
118 | $ is an anchor if it is at the end of a regular expression, or | ||
119 | before a close-group or an alternation operator. | ||
120 | |||
121 | This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because | ||
122 | POSIX draft 11.2 says that * etc. in leading positions is undefined. | ||
123 | We already implemented a previous draft which made those constructs | ||
124 | invalid, though, so we haven't changed the code back. */ | ||
125 | # define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) | ||
126 | |||
127 | /* If this bit is set, then special characters are always special | ||
128 | regardless of where they are in the pattern. | ||
129 | If this bit is not set, then special characters are special only in | ||
130 | some contexts; otherwise they are ordinary. Specifically, | ||
131 | * + ? and intervals are only special when not after the beginning, | ||
132 | open-group, or alternation operator. */ | ||
133 | # define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) | ||
134 | |||
135 | /* If this bit is set, then *, +, ?, and { cannot be first in an re or | ||
136 | immediately after an alternation or begin-group operator. */ | ||
137 | # define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) | ||
138 | |||
139 | /* If this bit is set, then . matches newline. | ||
140 | If not set, then it doesn't. */ | ||
141 | # define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) | ||
142 | |||
143 | /* If this bit is set, then . doesn't match NUL. | ||
144 | If not set, then it does. */ | ||
145 | # define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) | ||
146 | |||
147 | /* If this bit is set, nonmatching lists [^...] do not match newline. | ||
148 | If not set, they do. */ | ||
149 | # define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) | ||
150 | |||
151 | /* If this bit is set, either \{...\} or {...} defines an | ||
152 | interval, depending on RE_NO_BK_BRACES. | ||
153 | If not set, \{, \}, {, and } are literals. */ | ||
154 | # define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) | ||
155 | |||
156 | /* If this bit is set, +, ? and | aren't recognized as operators. | ||
157 | If not set, they are. */ | ||
158 | # define RE_LIMITED_OPS (RE_INTERVALS << 1) | ||
159 | |||
160 | /* If this bit is set, newline is an alternation operator. | ||
161 | If not set, newline is literal. */ | ||
162 | # define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) | ||
163 | |||
164 | /* If this bit is set, then `{...}' defines an interval, and \{ and \} | ||
165 | are literals. | ||
166 | If not set, then `\{...\}' defines an interval. */ | ||
167 | # define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) | ||
168 | |||
169 | /* If this bit is set, (...) defines a group, and \( and \) are literals. | ||
170 | If not set, \(...\) defines a group, and ( and ) are literals. */ | ||
171 | # define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) | ||
172 | |||
173 | /* If this bit is set, then \<digit> matches <digit>. | ||
174 | If not set, then \<digit> is a back-reference. */ | ||
175 | # define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) | ||
176 | |||
177 | /* If this bit is set, then | is an alternation operator, and \| is literal. | ||
178 | If not set, then \| is an alternation operator, and | is literal. */ | ||
179 | # define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) | ||
180 | |||
181 | /* If this bit is set, then an ending range point collating higher | ||
182 | than the starting range point, as in [z-a], is invalid. | ||
183 | If not set, then when ending range point collates higher than the | ||
184 | starting range point, the range is ignored. */ | ||
185 | # define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) | ||
186 | |||
187 | /* If this bit is set, then an unmatched ) is ordinary. | ||
188 | If not set, then an unmatched ) is invalid. */ | ||
189 | # define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) | ||
190 | |||
191 | /* If this bit is set, succeed as soon as we match the whole pattern, | ||
192 | without further backtracking. */ | ||
193 | # define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) | ||
194 | |||
195 | /* If this bit is set, do not process the GNU regex operators. | ||
196 | If not set, then the GNU regex operators are recognized. */ | ||
197 | # define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) | ||
198 | |||
199 | /* If this bit is set, turn on internal regex debugging. | ||
200 | If not set, and debugging was on, turn it off. | ||
201 | This only works if regex.c is compiled -DDEBUG. | ||
202 | We define this bit always, so that all that's needed to turn on | ||
203 | debugging is to recompile regex.c; the calling code can always have | ||
204 | this bit set, and it won't affect anything in the normal case. */ | ||
205 | # define RE_DEBUG (RE_NO_GNU_OPS << 1) | ||
206 | |||
207 | /* If this bit is set, a syntactically invalid interval is treated as | ||
208 | a string of ordinary characters. For example, the ERE 'a{1' is | ||
209 | treated as 'a\{1'. */ | ||
210 | # define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1) | ||
211 | |||
212 | /* If this bit is set, then ignore case when matching. | ||
213 | If not set, then case is significant. */ | ||
214 | # define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) | ||
215 | |||
216 | /* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only | ||
217 | for ^, because it is difficult to scan the regex backwards to find | ||
218 | whether ^ should be special. */ | ||
219 | # define RE_CARET_ANCHORS_HERE (RE_ICASE << 1) | ||
220 | |||
221 | /* If this bit is set, then \{ cannot be first in an bre or | ||
222 | immediately after an alternation or begin-group operator. */ | ||
223 | # define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1) | ||
224 | |||
225 | /* If this bit is set, then no_sub will be set to 1 during | ||
226 | re_compile_pattern. */ | ||
227 | # define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1) | ||
228 | |||
229 | #endif /* defined __USE_GNU_REGEX */ | ||
230 | |||
231 | /* This global variable defines the particular regexp syntax to use (for | ||
232 | some interfaces). When a regexp is compiled, the syntax used is | ||
233 | stored in the pattern buffer, so changing this does not affect | ||
234 | already-compiled regexps. */ | ||
235 | extern reg_syntax_t re_syntax_options; | ||
236 | |||
237 | #ifdef __USE_GNU_REGEX | ||
238 | /* Define combinations of the above bits for the standard possibilities. | ||
239 | (The [[[ comments delimit what gets put into the Texinfo file, so | ||
240 | don't delete them!) */ | ||
241 | /* [[[begin syntaxes]]] */ | ||
242 | # define RE_SYNTAX_EMACS 0 | ||
243 | |||
244 | # define RE_SYNTAX_AWK \ | ||
245 | (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ | ||
246 | | RE_NO_BK_PARENS | RE_NO_BK_REFS \ | ||
247 | | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ | ||
248 | | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ | ||
249 | | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) | ||
250 | |||
251 | # define RE_SYNTAX_GNU_AWK \ | ||
252 | ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \ | ||
253 | & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS \ | ||
254 | | RE_CONTEXT_INVALID_OPS )) | ||
255 | |||
256 | # define RE_SYNTAX_POSIX_AWK \ | ||
257 | (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ | ||
258 | | RE_INTERVALS | RE_NO_GNU_OPS) | ||
259 | |||
260 | # define RE_SYNTAX_GREP \ | ||
261 | (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ | ||
262 | | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ | ||
263 | | RE_NEWLINE_ALT) | ||
264 | |||
265 | # define RE_SYNTAX_EGREP \ | ||
266 | (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ | ||
267 | | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ | ||
268 | | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ | ||
269 | | RE_NO_BK_VBAR) | ||
270 | |||
271 | # define RE_SYNTAX_POSIX_EGREP \ | ||
272 | (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \ | ||
273 | | RE_INVALID_INTERVAL_ORD) | ||
274 | |||
275 | /* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ | ||
276 | # define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC | ||
277 | |||
278 | # define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC | ||
279 | |||
280 | /* Syntax bits common to both basic and extended POSIX regex syntax. */ | ||
281 | # define _RE_SYNTAX_POSIX_COMMON \ | ||
282 | (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ | ||
283 | | RE_INTERVALS | RE_NO_EMPTY_RANGES) | ||
284 | |||
285 | # define RE_SYNTAX_POSIX_BASIC \ | ||
286 | (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP) | ||
287 | |||
288 | /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes | ||
289 | RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this | ||
290 | isn't minimal, since other operators, such as \`, aren't disabled. */ | ||
291 | # define RE_SYNTAX_POSIX_MINIMAL_BASIC \ | ||
292 | (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) | ||
293 | |||
294 | # define RE_SYNTAX_POSIX_EXTENDED \ | ||
295 | (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | ||
296 | | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ | ||
297 | | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ | ||
298 | | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) | ||
299 | |||
300 | /* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is | ||
301 | removed and RE_NO_BK_REFS is added. */ | ||
302 | # define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ | ||
303 | (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | ||
304 | | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ | ||
305 | | RE_NO_BK_PARENS | RE_NO_BK_REFS \ | ||
306 | | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) | ||
307 | /* [[[end syntaxes]]] */ | ||
308 | |||
309 | #endif /* defined __USE_GNU_REGEX */ | ||
310 | |||
311 | #ifdef __USE_GNU_REGEX | ||
312 | |||
313 | /* Maximum number of duplicates an interval can allow. POSIX-conforming | ||
314 | systems might define this in <limits.h>, but we want our | ||
315 | value, so remove any previous define. */ | ||
316 | # ifdef RE_DUP_MAX | ||
317 | # undef RE_DUP_MAX | ||
318 | # endif | ||
319 | |||
320 | /* RE_DUP_MAX is 2**15 - 1 because an earlier implementation stored | ||
321 | the counter as a 2-byte signed integer. This is no longer true, so | ||
322 | RE_DUP_MAX could be increased to (INT_MAX / 10 - 1), or to | ||
323 | ((SIZE_MAX - 2) / 10 - 1) if _REGEX_LARGE_OFFSETS is defined. | ||
324 | However, there would be a huge performance problem if someone | ||
325 | actually used a pattern like a\{214748363\}, so RE_DUP_MAX retains | ||
326 | its historical value. */ | ||
327 | # define RE_DUP_MAX (0x7fff) | ||
328 | |||
329 | #endif /* defined __USE_GNU_REGEX */ | ||
330 | |||
331 | |||
332 | /* POSIX `cflags' bits (i.e., information for `regcomp'). */ | ||
333 | |||
334 | /* If this bit is set, then use extended regular expression syntax. | ||
335 | If not set, then use basic regular expression syntax. */ | ||
336 | #define REG_EXTENDED 1 | ||
337 | |||
338 | /* If this bit is set, then ignore case when matching. | ||
339 | If not set, then case is significant. */ | ||
340 | #define REG_ICASE (1 << 1) | ||
341 | |||
342 | /* If this bit is set, then anchors do not match at newline | ||
343 | characters in the string. | ||
344 | If not set, then anchors do match at newlines. */ | ||
345 | #define REG_NEWLINE (1 << 2) | ||
346 | |||
347 | /* If this bit is set, then report only success or fail in regexec. | ||
348 | If not set, then returns differ between not matching and errors. */ | ||
349 | #define REG_NOSUB (1 << 3) | ||
350 | |||
351 | |||
352 | /* POSIX `eflags' bits (i.e., information for regexec). */ | ||
353 | |||
354 | /* If this bit is set, then the beginning-of-line operator doesn't match | ||
355 | the beginning of the string (presumably because it's not the | ||
356 | beginning of a line). | ||
357 | If not set, then the beginning-of-line operator does match the | ||
358 | beginning of the string. */ | ||
359 | #define REG_NOTBOL 1 | ||
360 | |||
361 | /* Like REG_NOTBOL, except for the end-of-line. */ | ||
362 | #define REG_NOTEOL (1 << 1) | ||
363 | |||
364 | /* Use PMATCH[0] to delimit the start and end of the search in the | ||
365 | buffer. */ | ||
366 | #define REG_STARTEND (1 << 2) | ||
367 | |||
368 | |||
369 | /* If any error codes are removed, changed, or added, update the | ||
370 | `__re_error_msgid' table in regcomp.c. */ | ||
371 | |||
372 | typedef enum | ||
373 | { | ||
374 | _REG_ENOSYS = -1, /* This will never happen for this implementation. */ | ||
375 | _REG_NOERROR = 0, /* Success. */ | ||
376 | _REG_NOMATCH, /* Didn't find a match (for regexec). */ | ||
377 | |||
378 | /* POSIX regcomp return error codes. (In the order listed in the | ||
379 | standard.) */ | ||
380 | _REG_BADPAT, /* Invalid pattern. */ | ||
381 | _REG_ECOLLATE, /* Invalid collating element. */ | ||
382 | _REG_ECTYPE, /* Invalid character class name. */ | ||
383 | _REG_EESCAPE, /* Trailing backslash. */ | ||
384 | _REG_ESUBREG, /* Invalid back reference. */ | ||
385 | _REG_EBRACK, /* Unmatched left bracket. */ | ||
386 | _REG_EPAREN, /* Parenthesis imbalance. */ | ||
387 | _REG_EBRACE, /* Unmatched \{. */ | ||
388 | _REG_BADBR, /* Invalid contents of \{\}. */ | ||
389 | _REG_ERANGE, /* Invalid range end. */ | ||
390 | _REG_ESPACE, /* Ran out of memory. */ | ||
391 | _REG_BADRPT, /* No preceding re for repetition op. */ | ||
392 | |||
393 | /* Error codes we've added. */ | ||
394 | _REG_EEND, /* Premature end. */ | ||
395 | _REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ | ||
396 | _REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ | ||
397 | } reg_errcode_t; | ||
398 | |||
399 | #ifdef _XOPEN_SOURCE | ||
400 | # define REG_ENOSYS _REG_ENOSYS | ||
401 | #endif | ||
402 | #define REG_NOERROR _REG_NOERROR | ||
403 | #define REG_NOMATCH _REG_NOMATCH | ||
404 | #define REG_BADPAT _REG_BADPAT | ||
405 | #define REG_ECOLLATE _REG_ECOLLATE | ||
406 | #define REG_ECTYPE _REG_ECTYPE | ||
407 | #define REG_EESCAPE _REG_EESCAPE | ||
408 | #define REG_ESUBREG _REG_ESUBREG | ||
409 | #define REG_EBRACK _REG_EBRACK | ||
410 | #define REG_EPAREN _REG_EPAREN | ||
411 | #define REG_EBRACE _REG_EBRACE | ||
412 | #define REG_BADBR _REG_BADBR | ||
413 | #define REG_ERANGE _REG_ERANGE | ||
414 | #define REG_ESPACE _REG_ESPACE | ||
415 | #define REG_BADRPT _REG_BADRPT | ||
416 | #define REG_EEND _REG_EEND | ||
417 | #define REG_ESIZE _REG_ESIZE | ||
418 | #define REG_ERPAREN _REG_ERPAREN | ||
419 | |||
420 | /* struct re_pattern_buffer normally uses member names like `buffer' | ||
421 | that POSIX does not allow. In POSIX mode these members have names | ||
422 | with leading `re_' (e.g., `re_buffer'). */ | ||
423 | #ifdef __USE_GNU_REGEX | ||
424 | # define _REG_RE_NAME(id) id | ||
425 | # define _REG_RM_NAME(id) id | ||
426 | #else | ||
427 | # define _REG_RE_NAME(id) re_##id | ||
428 | # define _REG_RM_NAME(id) rm_##id | ||
429 | #endif | ||
430 | |||
431 | /* The user can specify the type of the re_translate member by | ||
432 | defining the macro RE_TRANSLATE_TYPE, which defaults to unsigned | ||
433 | char *. This pollutes the POSIX name space, so in POSIX mode just | ||
434 | use unsigned char *. */ | ||
435 | #ifdef __USE_GNU_REGEX | ||
436 | # ifndef RE_TRANSLATE_TYPE | ||
437 | # define RE_TRANSLATE_TYPE unsigned char * | ||
438 | # endif | ||
439 | # define REG_TRANSLATE_TYPE RE_TRANSLATE_TYPE | ||
440 | #else | ||
441 | # define REG_TRANSLATE_TYPE unsigned char * | ||
442 | #endif | ||
443 | |||
444 | /* This data structure represents a compiled pattern. Before calling | ||
445 | the pattern compiler, the fields `buffer', `allocated', `fastmap', | ||
446 | `translate', and `no_sub' can be set. After the pattern has been | ||
447 | compiled, the `re_nsub' field is available. All other fields are | ||
448 | private to the regex routines. */ | ||
449 | |||
450 | struct re_pattern_buffer | ||
451 | { | ||
452 | /* Space that holds the compiled pattern. It is declared as | ||
453 | `unsigned char *' because its elements are sometimes used as | ||
454 | array indexes. */ | ||
455 | unsigned char *_REG_RE_NAME (buffer); | ||
456 | |||
457 | /* Number of bytes to which `buffer' points. */ | ||
458 | __re_long_size_t _REG_RE_NAME (allocated); | ||
459 | |||
460 | /* Number of bytes actually used in `buffer'. */ | ||
461 | __re_long_size_t _REG_RE_NAME (used); | ||
462 | |||
463 | /* Syntax setting with which the pattern was compiled. */ | ||
464 | reg_syntax_t _REG_RE_NAME (syntax); | ||
465 | |||
466 | /* Pointer to a fastmap, if any, otherwise zero. re_search uses the | ||
467 | fastmap, if there is one, to skip over impossible starting points | ||
468 | for matches. */ | ||
469 | char *_REG_RE_NAME (fastmap); | ||
470 | |||
471 | /* Either a translate table to apply to all characters before | ||
472 | comparing them, or zero for no translation. The translation is | ||
473 | applied to a pattern when it is compiled and to a string when it | ||
474 | is matched. */ | ||
475 | REG_TRANSLATE_TYPE _REG_RE_NAME (translate); | ||
476 | |||
477 | /* Number of subexpressions found by the compiler. */ | ||
478 | size_t re_nsub; | ||
479 | |||
480 | /* Zero if this pattern cannot match the empty string, one else. | ||
481 | Well, in truth it's used only in `re_search_2', to see whether or | ||
482 | not we should use the fastmap, so we don't set this absolutely | ||
483 | perfectly; see `re_compile_fastmap' (the `duplicate' case). */ | ||
484 | unsigned int _REG_RE_NAME (can_be_null) : 1; | ||
485 | |||
486 | /* If REGS_UNALLOCATED, allocate space in the `regs' structure | ||
487 | for `max (RE_NREGS, re_nsub + 1)' groups. | ||
488 | If REGS_REALLOCATE, reallocate space if necessary. | ||
489 | If REGS_FIXED, use what's there. */ | ||
490 | #ifdef __USE_GNU_REGEX | ||
491 | # define REGS_UNALLOCATED 0 | ||
492 | # define REGS_REALLOCATE 1 | ||
493 | # define REGS_FIXED 2 | ||
494 | #endif | ||
495 | unsigned int _REG_RE_NAME (regs_allocated) : 2; | ||
496 | |||
497 | /* Set to zero when `regex_compile' compiles a pattern; set to one | ||
498 | by `re_compile_fastmap' if it updates the fastmap. */ | ||
499 | unsigned int _REG_RE_NAME (fastmap_accurate) : 1; | ||
500 | |||
501 | /* If set, `re_match_2' does not return information about | ||
502 | subexpressions. */ | ||
503 | unsigned int _REG_RE_NAME (no_sub) : 1; | ||
504 | |||
505 | /* If set, a beginning-of-line anchor doesn't match at the beginning | ||
506 | of the string. */ | ||
507 | unsigned int _REG_RE_NAME (not_bol) : 1; | ||
508 | |||
509 | /* Similarly for an end-of-line anchor. */ | ||
510 | unsigned int _REG_RE_NAME (not_eol) : 1; | ||
511 | |||
512 | /* If true, an anchor at a newline matches. */ | ||
513 | unsigned int _REG_RE_NAME (newline_anchor) : 1; | ||
514 | |||
515 | /* [[[end pattern_buffer]]] */ | ||
516 | }; | ||
517 | |||
518 | typedef struct re_pattern_buffer regex_t; | ||
519 | |||
520 | /* This is the structure we store register match data in. See | ||
521 | regex.texinfo for a full description of what registers match. */ | ||
522 | struct re_registers | ||
523 | { | ||
524 | __re_size_t _REG_RM_NAME (num_regs); | ||
525 | regoff_t *_REG_RM_NAME (start); | ||
526 | regoff_t *_REG_RM_NAME (end); | ||
527 | }; | ||
528 | |||
529 | |||
530 | /* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, | ||
531 | `re_match_2' returns information about at least this many registers | ||
532 | the first time a `regs' structure is passed. */ | ||
533 | #if !defined RE_NREGS && defined __USE_GNU_REGEX | ||
534 | # define RE_NREGS 30 | ||
535 | #endif | ||
536 | |||
537 | |||
538 | /* POSIX specification for registers. Aside from the different names than | ||
539 | `re_registers', POSIX uses an array of structures, instead of a | ||
540 | structure of arrays. */ | ||
541 | typedef struct | ||
542 | { | ||
543 | regoff_t rm_so; /* Byte offset from string's start to substring's start. */ | ||
544 | regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ | ||
545 | } regmatch_t; | ||
546 | |||
547 | /* Declarations for routines. */ | ||
548 | |||
549 | /* Sets the current default syntax to SYNTAX, and return the old syntax. | ||
550 | You can also simply assign to the `re_syntax_options' variable. */ | ||
551 | extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); | ||
552 | |||
553 | /* Compile the regular expression PATTERN, with length LENGTH | ||
554 | and syntax given by the global `re_syntax_options', into the buffer | ||
555 | BUFFER. Return NULL if successful, and an error string if not. */ | ||
556 | extern const char *re_compile_pattern (const char *__pattern, size_t __length, | ||
557 | struct re_pattern_buffer *__buffer); | ||
558 | |||
559 | |||
560 | /* Compile a fastmap for the compiled pattern in BUFFER; used to | ||
561 | accelerate searches. Return 0 if successful and -2 if was an | ||
562 | internal error. */ | ||
563 | extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); | ||
564 | |||
565 | |||
566 | /* Search in the string STRING (with length LENGTH) for the pattern | ||
567 | compiled into BUFFER. Start searching at position START, for RANGE | ||
568 | characters. Return the starting position of the match, -1 for no | ||
569 | match, or -2 for an internal error. Also return register | ||
570 | information in REGS (if REGS and BUFFER->no_sub are nonzero). */ | ||
571 | extern regoff_t re_search (struct re_pattern_buffer *__buffer, | ||
572 | const char *__string, __re_idx_t __length, | ||
573 | __re_idx_t __start, regoff_t __range, | ||
574 | struct re_registers *__regs); | ||
575 | |||
576 | |||
577 | /* Like `re_search', but search in the concatenation of STRING1 and | ||
578 | STRING2. Also, stop searching at index START + STOP. */ | ||
579 | extern regoff_t re_search_2 (struct re_pattern_buffer *__buffer, | ||
580 | const char *__string1, __re_idx_t __length1, | ||
581 | const char *__string2, __re_idx_t __length2, | ||
582 | __re_idx_t __start, regoff_t __range, | ||
583 | struct re_registers *__regs, | ||
584 | __re_idx_t __stop); | ||
585 | |||
586 | |||
587 | /* Like `re_search', but return how many characters in STRING the regexp | ||
588 | in BUFFER matched, starting at position START. */ | ||
589 | extern regoff_t re_match (struct re_pattern_buffer *__buffer, | ||
590 | const char *__string, __re_idx_t __length, | ||
591 | __re_idx_t __start, struct re_registers *__regs); | ||
592 | |||
593 | |||
594 | /* Relates to `re_match' as `re_search_2' relates to `re_search'. */ | ||
595 | extern regoff_t re_match_2 (struct re_pattern_buffer *__buffer, | ||
596 | const char *__string1, __re_idx_t __length1, | ||
597 | const char *__string2, __re_idx_t __length2, | ||
598 | __re_idx_t __start, struct re_registers *__regs, | ||
599 | __re_idx_t __stop); | ||
600 | |||
601 | |||
602 | /* Set REGS to hold NUM_REGS registers, storing them in STARTS and | ||
603 | ENDS. Subsequent matches using BUFFER and REGS will use this memory | ||
604 | for recording register information. STARTS and ENDS must be | ||
605 | allocated with malloc, and must each be at least `NUM_REGS * sizeof | ||
606 | (regoff_t)' bytes long. | ||
607 | |||
608 | If NUM_REGS == 0, then subsequent matches should allocate their own | ||
609 | register data. | ||
610 | |||
611 | Unless this function is called, the first search or match using | ||
612 | PATTERN_BUFFER will allocate its own register data, without | ||
613 | freeing the old data. */ | ||
614 | extern void re_set_registers (struct re_pattern_buffer *__buffer, | ||
615 | struct re_registers *__regs, | ||
616 | __re_size_t __num_regs, | ||
617 | regoff_t *__starts, regoff_t *__ends); | ||
618 | |||
619 | #if defined _REGEX_RE_COMP || defined _LIBC | ||
620 | # ifndef _CRAY | ||
621 | /* 4.2 bsd compatibility. */ | ||
622 | extern char *re_comp (const char *); | ||
623 | extern int re_exec (const char *); | ||
624 | # endif | ||
625 | #endif | ||
626 | |||
627 | /* GCC 2.95 and later have "__restrict"; C99 compilers have | ||
628 | "restrict", and "configure" may have defined "restrict". */ | ||
629 | #ifndef __restrict | ||
630 | # if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) | ||
631 | # if defined restrict || 199901L <= __STDC_VERSION__ | ||
632 | # define __restrict restrict | ||
633 | # else | ||
634 | # define __restrict | ||
635 | # endif | ||
636 | # endif | ||
637 | #endif | ||
638 | /* gcc 3.1 and up support the [restrict] syntax. Don't trust | ||
639 | sys/cdefs.h's definition of __restrict_arr, though, as it | ||
640 | mishandles gcc -ansi -pedantic. */ | ||
641 | #undef __restrict_arr | ||
642 | #if ((199901L <= __STDC_VERSION__ \ | ||
643 | || ((3 < __GNUC__ || (3 == __GNUC__ && 1 <= __GNUC_MINOR__)) \ | ||
644 | && !__STRICT_ANSI__)) \ | ||
645 | && !defined __GNUG__) | ||
646 | # define __restrict_arr __restrict | ||
647 | #else | ||
648 | # define __restrict_arr | ||
649 | #endif | ||
650 | |||
651 | /* POSIX compatibility. */ | ||
652 | extern int regcomp (regex_t *__restrict __preg, | ||
653 | const char *__restrict __pattern, | ||
654 | int __cflags); | ||
655 | |||
656 | extern int regexec (const regex_t *__restrict __preg, | ||
657 | const char *__restrict __string, size_t __nmatch, | ||
658 | regmatch_t __pmatch[__restrict_arr], | ||
659 | int __eflags); | ||
660 | |||
661 | extern size_t regerror (int __errcode, const regex_t *__restrict __preg, | ||
662 | char *__restrict __errbuf, size_t __errbuf_size); | ||
663 | |||
664 | extern void regfree (regex_t *__preg); | ||
665 | |||
666 | |||
667 | #ifdef __cplusplus | ||
668 | } | ||
669 | #endif /* C++ */ | ||
670 | |||
671 | #endif /* regex.h */ | ||
diff --git a/gl/regex_internal.c b/gl/regex_internal.c new file mode 100644 index 00000000..78e16f33 --- /dev/null +++ b/gl/regex_internal.c | |||
@@ -0,0 +1,1742 @@ | |||
1 | /* Extended regular expression matching and search library. | ||
2 | Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. | ||
3 | This file is part of the GNU C Library. | ||
4 | Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License along | ||
17 | with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | static void re_string_construct_common (const char *str, Idx len, | ||
21 | re_string_t *pstr, | ||
22 | RE_TRANSLATE_TYPE trans, bool icase, | ||
23 | const re_dfa_t *dfa) internal_function; | ||
24 | static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa, | ||
25 | const re_node_set *nodes, | ||
26 | re_hashval_t hash) internal_function; | ||
27 | static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa, | ||
28 | const re_node_set *nodes, | ||
29 | unsigned int context, | ||
30 | re_hashval_t hash) internal_function; | ||
31 | |||
32 | /* Functions for string operation. */ | ||
33 | |||
34 | /* This function allocate the buffers. It is necessary to call | ||
35 | re_string_reconstruct before using the object. */ | ||
36 | |||
37 | static reg_errcode_t | ||
38 | internal_function | ||
39 | re_string_allocate (re_string_t *pstr, const char *str, Idx len, Idx init_len, | ||
40 | RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa) | ||
41 | { | ||
42 | reg_errcode_t ret; | ||
43 | Idx init_buf_len; | ||
44 | |||
45 | /* Ensure at least one character fits into the buffers. */ | ||
46 | if (init_len < dfa->mb_cur_max) | ||
47 | init_len = dfa->mb_cur_max; | ||
48 | init_buf_len = (len + 1 < init_len) ? len + 1: init_len; | ||
49 | re_string_construct_common (str, len, pstr, trans, icase, dfa); | ||
50 | |||
51 | ret = re_string_realloc_buffers (pstr, init_buf_len); | ||
52 | if (BE (ret != REG_NOERROR, 0)) | ||
53 | return ret; | ||
54 | |||
55 | pstr->word_char = dfa->word_char; | ||
56 | pstr->word_ops_used = dfa->word_ops_used; | ||
57 | pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; | ||
58 | pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len; | ||
59 | pstr->valid_raw_len = pstr->valid_len; | ||
60 | return REG_NOERROR; | ||
61 | } | ||
62 | |||
63 | /* This function allocate the buffers, and initialize them. */ | ||
64 | |||
65 | static reg_errcode_t | ||
66 | internal_function | ||
67 | re_string_construct (re_string_t *pstr, const char *str, Idx len, | ||
68 | RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa) | ||
69 | { | ||
70 | reg_errcode_t ret; | ||
71 | memset (pstr, '\0', sizeof (re_string_t)); | ||
72 | re_string_construct_common (str, len, pstr, trans, icase, dfa); | ||
73 | |||
74 | if (len > 0) | ||
75 | { | ||
76 | ret = re_string_realloc_buffers (pstr, len + 1); | ||
77 | if (BE (ret != REG_NOERROR, 0)) | ||
78 | return ret; | ||
79 | } | ||
80 | pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; | ||
81 | |||
82 | if (icase) | ||
83 | { | ||
84 | #ifdef RE_ENABLE_I18N | ||
85 | if (dfa->mb_cur_max > 1) | ||
86 | { | ||
87 | while (1) | ||
88 | { | ||
89 | ret = build_wcs_upper_buffer (pstr); | ||
90 | if (BE (ret != REG_NOERROR, 0)) | ||
91 | return ret; | ||
92 | if (pstr->valid_raw_len >= len) | ||
93 | break; | ||
94 | if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max) | ||
95 | break; | ||
96 | ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); | ||
97 | if (BE (ret != REG_NOERROR, 0)) | ||
98 | return ret; | ||
99 | } | ||
100 | } | ||
101 | else | ||
102 | #endif /* RE_ENABLE_I18N */ | ||
103 | build_upper_buffer (pstr); | ||
104 | } | ||
105 | else | ||
106 | { | ||
107 | #ifdef RE_ENABLE_I18N | ||
108 | if (dfa->mb_cur_max > 1) | ||
109 | build_wcs_buffer (pstr); | ||
110 | else | ||
111 | #endif /* RE_ENABLE_I18N */ | ||
112 | { | ||
113 | if (trans != NULL) | ||
114 | re_string_translate_buffer (pstr); | ||
115 | else | ||
116 | { | ||
117 | pstr->valid_len = pstr->bufs_len; | ||
118 | pstr->valid_raw_len = pstr->bufs_len; | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | return REG_NOERROR; | ||
124 | } | ||
125 | |||
126 | /* Helper functions for re_string_allocate, and re_string_construct. */ | ||
127 | |||
128 | static reg_errcode_t | ||
129 | internal_function | ||
130 | re_string_realloc_buffers (re_string_t *pstr, Idx new_buf_len) | ||
131 | { | ||
132 | #ifdef RE_ENABLE_I18N | ||
133 | if (pstr->mb_cur_max > 1) | ||
134 | { | ||
135 | wint_t *new_wcs; | ||
136 | |||
137 | /* Avoid overflow. */ | ||
138 | size_t max_object_size = MAX (sizeof (wint_t), sizeof (Idx)); | ||
139 | if (BE (SIZE_MAX / max_object_size < new_buf_len, 0)) | ||
140 | return REG_ESPACE; | ||
141 | |||
142 | new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len); | ||
143 | if (BE (new_wcs == NULL, 0)) | ||
144 | return REG_ESPACE; | ||
145 | pstr->wcs = new_wcs; | ||
146 | if (pstr->offsets != NULL) | ||
147 | { | ||
148 | Idx *new_offsets = re_realloc (pstr->offsets, Idx, new_buf_len); | ||
149 | if (BE (new_offsets == NULL, 0)) | ||
150 | return REG_ESPACE; | ||
151 | pstr->offsets = new_offsets; | ||
152 | } | ||
153 | } | ||
154 | #endif /* RE_ENABLE_I18N */ | ||
155 | if (pstr->mbs_allocated) | ||
156 | { | ||
157 | unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char, | ||
158 | new_buf_len); | ||
159 | if (BE (new_mbs == NULL, 0)) | ||
160 | return REG_ESPACE; | ||
161 | pstr->mbs = new_mbs; | ||
162 | } | ||
163 | pstr->bufs_len = new_buf_len; | ||
164 | return REG_NOERROR; | ||
165 | } | ||
166 | |||
167 | |||
168 | static void | ||
169 | internal_function | ||
170 | re_string_construct_common (const char *str, Idx len, re_string_t *pstr, | ||
171 | RE_TRANSLATE_TYPE trans, bool icase, | ||
172 | const re_dfa_t *dfa) | ||
173 | { | ||
174 | pstr->raw_mbs = (const unsigned char *) str; | ||
175 | pstr->len = len; | ||
176 | pstr->raw_len = len; | ||
177 | pstr->trans = trans; | ||
178 | pstr->icase = icase; | ||
179 | pstr->mbs_allocated = (trans != NULL || icase); | ||
180 | pstr->mb_cur_max = dfa->mb_cur_max; | ||
181 | pstr->is_utf8 = dfa->is_utf8; | ||
182 | pstr->map_notascii = dfa->map_notascii; | ||
183 | pstr->stop = pstr->len; | ||
184 | pstr->raw_stop = pstr->stop; | ||
185 | } | ||
186 | |||
187 | #ifdef RE_ENABLE_I18N | ||
188 | |||
189 | /* Build wide character buffer PSTR->WCS. | ||
190 | If the byte sequence of the string are: | ||
191 | <mb1>(0), <mb1>(1), <mb2>(0), <mb2>(1), <sb3> | ||
192 | Then wide character buffer will be: | ||
193 | <wc1> , WEOF , <wc2> , WEOF , <wc3> | ||
194 | We use WEOF for padding, they indicate that the position isn't | ||
195 | a first byte of a multibyte character. | ||
196 | |||
197 | Note that this function assumes PSTR->VALID_LEN elements are already | ||
198 | built and starts from PSTR->VALID_LEN. */ | ||
199 | |||
200 | static void | ||
201 | internal_function | ||
202 | build_wcs_buffer (re_string_t *pstr) | ||
203 | { | ||
204 | #ifdef _LIBC | ||
205 | unsigned char buf[MB_LEN_MAX]; | ||
206 | assert (MB_LEN_MAX >= pstr->mb_cur_max); | ||
207 | #else | ||
208 | unsigned char buf[64]; | ||
209 | #endif | ||
210 | mbstate_t prev_st; | ||
211 | Idx byte_idx, end_idx, remain_len; | ||
212 | size_t mbclen; | ||
213 | |||
214 | /* Build the buffers from pstr->valid_len to either pstr->len or | ||
215 | pstr->bufs_len. */ | ||
216 | end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; | ||
217 | for (byte_idx = pstr->valid_len; byte_idx < end_idx;) | ||
218 | { | ||
219 | wchar_t wc; | ||
220 | const char *p; | ||
221 | |||
222 | remain_len = end_idx - byte_idx; | ||
223 | prev_st = pstr->cur_state; | ||
224 | /* Apply the translation if we need. */ | ||
225 | if (BE (pstr->trans != NULL, 0)) | ||
226 | { | ||
227 | int i, ch; | ||
228 | |||
229 | for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i) | ||
230 | { | ||
231 | ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i]; | ||
232 | buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch]; | ||
233 | } | ||
234 | p = (const char *) buf; | ||
235 | } | ||
236 | else | ||
237 | p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx; | ||
238 | mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state); | ||
239 | if (BE (mbclen == (size_t) -2, 0)) | ||
240 | { | ||
241 | /* The buffer doesn't have enough space, finish to build. */ | ||
242 | pstr->cur_state = prev_st; | ||
243 | break; | ||
244 | } | ||
245 | else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0)) | ||
246 | { | ||
247 | /* We treat these cases as a singlebyte character. */ | ||
248 | mbclen = 1; | ||
249 | wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; | ||
250 | if (BE (pstr->trans != NULL, 0)) | ||
251 | wc = pstr->trans[wc]; | ||
252 | pstr->cur_state = prev_st; | ||
253 | } | ||
254 | |||
255 | /* Write wide character and padding. */ | ||
256 | pstr->wcs[byte_idx++] = wc; | ||
257 | /* Write paddings. */ | ||
258 | for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) | ||
259 | pstr->wcs[byte_idx++] = WEOF; | ||
260 | } | ||
261 | pstr->valid_len = byte_idx; | ||
262 | pstr->valid_raw_len = byte_idx; | ||
263 | } | ||
264 | |||
265 | /* Build wide character buffer PSTR->WCS like build_wcs_buffer, | ||
266 | but for REG_ICASE. */ | ||
267 | |||
268 | static reg_errcode_t | ||
269 | internal_function | ||
270 | build_wcs_upper_buffer (re_string_t *pstr) | ||
271 | { | ||
272 | mbstate_t prev_st; | ||
273 | Idx src_idx, byte_idx, end_idx, remain_len; | ||
274 | size_t mbclen; | ||
275 | #ifdef _LIBC | ||
276 | char buf[MB_LEN_MAX]; | ||
277 | assert (MB_LEN_MAX >= pstr->mb_cur_max); | ||
278 | #else | ||
279 | char buf[64]; | ||
280 | #endif | ||
281 | |||
282 | byte_idx = pstr->valid_len; | ||
283 | end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; | ||
284 | |||
285 | /* The following optimization assumes that ASCII characters can be | ||
286 | mapped to wide characters with a simple cast. */ | ||
287 | if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed) | ||
288 | { | ||
289 | while (byte_idx < end_idx) | ||
290 | { | ||
291 | wchar_t wc; | ||
292 | |||
293 | if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]) | ||
294 | && mbsinit (&pstr->cur_state)) | ||
295 | { | ||
296 | /* In case of a singlebyte character. */ | ||
297 | pstr->mbs[byte_idx] | ||
298 | = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]); | ||
299 | /* The next step uses the assumption that wchar_t is encoded | ||
300 | ASCII-safe: all ASCII values can be converted like this. */ | ||
301 | pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx]; | ||
302 | ++byte_idx; | ||
303 | continue; | ||
304 | } | ||
305 | |||
306 | remain_len = end_idx - byte_idx; | ||
307 | prev_st = pstr->cur_state; | ||
308 | mbclen = mbrtowc (&wc, | ||
309 | ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx | ||
310 | + byte_idx), remain_len, &pstr->cur_state); | ||
311 | if (BE (mbclen < (size_t) -2, 1)) | ||
312 | { | ||
313 | wchar_t wcu = wc; | ||
314 | if (iswlower (wc)) | ||
315 | { | ||
316 | size_t mbcdlen; | ||
317 | |||
318 | wcu = towupper (wc); | ||
319 | mbcdlen = wcrtomb (buf, wcu, &prev_st); | ||
320 | if (BE (mbclen == mbcdlen, 1)) | ||
321 | memcpy (pstr->mbs + byte_idx, buf, mbclen); | ||
322 | else | ||
323 | { | ||
324 | src_idx = byte_idx; | ||
325 | goto offsets_needed; | ||
326 | } | ||
327 | } | ||
328 | else | ||
329 | memcpy (pstr->mbs + byte_idx, | ||
330 | pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen); | ||
331 | pstr->wcs[byte_idx++] = wcu; | ||
332 | /* Write paddings. */ | ||
333 | for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) | ||
334 | pstr->wcs[byte_idx++] = WEOF; | ||
335 | } | ||
336 | else if (mbclen == (size_t) -1 || mbclen == 0) | ||
337 | { | ||
338 | /* It is an invalid character or '\0'. Just use the byte. */ | ||
339 | int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; | ||
340 | pstr->mbs[byte_idx] = ch; | ||
341 | /* And also cast it to wide char. */ | ||
342 | pstr->wcs[byte_idx++] = (wchar_t) ch; | ||
343 | if (BE (mbclen == (size_t) -1, 0)) | ||
344 | pstr->cur_state = prev_st; | ||
345 | } | ||
346 | else | ||
347 | { | ||
348 | /* The buffer doesn't have enough space, finish to build. */ | ||
349 | pstr->cur_state = prev_st; | ||
350 | break; | ||
351 | } | ||
352 | } | ||
353 | pstr->valid_len = byte_idx; | ||
354 | pstr->valid_raw_len = byte_idx; | ||
355 | return REG_NOERROR; | ||
356 | } | ||
357 | else | ||
358 | for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;) | ||
359 | { | ||
360 | wchar_t wc; | ||
361 | const char *p; | ||
362 | offsets_needed: | ||
363 | remain_len = end_idx - byte_idx; | ||
364 | prev_st = pstr->cur_state; | ||
365 | if (BE (pstr->trans != NULL, 0)) | ||
366 | { | ||
367 | int i, ch; | ||
368 | |||
369 | for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i) | ||
370 | { | ||
371 | ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i]; | ||
372 | buf[i] = pstr->trans[ch]; | ||
373 | } | ||
374 | p = (const char *) buf; | ||
375 | } | ||
376 | else | ||
377 | p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx; | ||
378 | mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state); | ||
379 | if (BE (mbclen < (size_t) -2, 1)) | ||
380 | { | ||
381 | wchar_t wcu = wc; | ||
382 | if (iswlower (wc)) | ||
383 | { | ||
384 | size_t mbcdlen; | ||
385 | |||
386 | wcu = towupper (wc); | ||
387 | mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st); | ||
388 | if (BE (mbclen == mbcdlen, 1)) | ||
389 | memcpy (pstr->mbs + byte_idx, buf, mbclen); | ||
390 | else if (mbcdlen != (size_t) -1) | ||
391 | { | ||
392 | size_t i; | ||
393 | |||
394 | if (byte_idx + mbcdlen > pstr->bufs_len) | ||
395 | { | ||
396 | pstr->cur_state = prev_st; | ||
397 | break; | ||
398 | } | ||
399 | |||
400 | if (pstr->offsets == NULL) | ||
401 | { | ||
402 | pstr->offsets = re_malloc (Idx, pstr->bufs_len); | ||
403 | |||
404 | if (pstr->offsets == NULL) | ||
405 | return REG_ESPACE; | ||
406 | } | ||
407 | if (!pstr->offsets_needed) | ||
408 | { | ||
409 | for (i = 0; i < (size_t) byte_idx; ++i) | ||
410 | pstr->offsets[i] = i; | ||
411 | pstr->offsets_needed = 1; | ||
412 | } | ||
413 | |||
414 | memcpy (pstr->mbs + byte_idx, buf, mbcdlen); | ||
415 | pstr->wcs[byte_idx] = wcu; | ||
416 | pstr->offsets[byte_idx] = src_idx; | ||
417 | for (i = 1; i < mbcdlen; ++i) | ||
418 | { | ||
419 | pstr->offsets[byte_idx + i] | ||
420 | = src_idx + (i < mbclen ? i : mbclen - 1); | ||
421 | pstr->wcs[byte_idx + i] = WEOF; | ||
422 | } | ||
423 | pstr->len += mbcdlen - mbclen; | ||
424 | if (pstr->raw_stop > src_idx) | ||
425 | pstr->stop += mbcdlen - mbclen; | ||
426 | end_idx = (pstr->bufs_len > pstr->len) | ||
427 | ? pstr->len : pstr->bufs_len; | ||
428 | byte_idx += mbcdlen; | ||
429 | src_idx += mbclen; | ||
430 | continue; | ||
431 | } | ||
432 | else | ||
433 | memcpy (pstr->mbs + byte_idx, p, mbclen); | ||
434 | } | ||
435 | else | ||
436 | memcpy (pstr->mbs + byte_idx, p, mbclen); | ||
437 | |||
438 | if (BE (pstr->offsets_needed != 0, 0)) | ||
439 | { | ||
440 | size_t i; | ||
441 | for (i = 0; i < mbclen; ++i) | ||
442 | pstr->offsets[byte_idx + i] = src_idx + i; | ||
443 | } | ||
444 | src_idx += mbclen; | ||
445 | |||
446 | pstr->wcs[byte_idx++] = wcu; | ||
447 | /* Write paddings. */ | ||
448 | for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) | ||
449 | pstr->wcs[byte_idx++] = WEOF; | ||
450 | } | ||
451 | else if (mbclen == (size_t) -1 || mbclen == 0) | ||
452 | { | ||
453 | /* It is an invalid character or '\0'. Just use the byte. */ | ||
454 | int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx]; | ||
455 | |||
456 | if (BE (pstr->trans != NULL, 0)) | ||
457 | ch = pstr->trans [ch]; | ||
458 | pstr->mbs[byte_idx] = ch; | ||
459 | |||
460 | if (BE (pstr->offsets_needed != 0, 0)) | ||
461 | pstr->offsets[byte_idx] = src_idx; | ||
462 | ++src_idx; | ||
463 | |||
464 | /* And also cast it to wide char. */ | ||
465 | pstr->wcs[byte_idx++] = (wchar_t) ch; | ||
466 | if (BE (mbclen == (size_t) -1, 0)) | ||
467 | pstr->cur_state = prev_st; | ||
468 | } | ||
469 | else | ||
470 | { | ||
471 | /* The buffer doesn't have enough space, finish to build. */ | ||
472 | pstr->cur_state = prev_st; | ||
473 | break; | ||
474 | } | ||
475 | } | ||
476 | pstr->valid_len = byte_idx; | ||
477 | pstr->valid_raw_len = src_idx; | ||
478 | return REG_NOERROR; | ||
479 | } | ||
480 | |||
481 | /* Skip characters until the index becomes greater than NEW_RAW_IDX. | ||
482 | Return the index. */ | ||
483 | |||
484 | static Idx | ||
485 | internal_function | ||
486 | re_string_skip_chars (re_string_t *pstr, Idx new_raw_idx, wint_t *last_wc) | ||
487 | { | ||
488 | mbstate_t prev_st; | ||
489 | Idx rawbuf_idx; | ||
490 | size_t mbclen; | ||
491 | wint_t wc = WEOF; | ||
492 | |||
493 | /* Skip the characters which are not necessary to check. */ | ||
494 | for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len; | ||
495 | rawbuf_idx < new_raw_idx;) | ||
496 | { | ||
497 | wchar_t wc2; | ||
498 | Idx remain_len; | ||
499 | remain_len = pstr->len - rawbuf_idx; | ||
500 | prev_st = pstr->cur_state; | ||
501 | mbclen = mbrtowc (&wc2, (const char *) pstr->raw_mbs + rawbuf_idx, | ||
502 | remain_len, &pstr->cur_state); | ||
503 | if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0)) | ||
504 | { | ||
505 | /* We treat these cases as a single byte character. */ | ||
506 | if (mbclen == 0 || remain_len == 0) | ||
507 | wc = L'\0'; | ||
508 | else | ||
509 | wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx); | ||
510 | mbclen = 1; | ||
511 | pstr->cur_state = prev_st; | ||
512 | } | ||
513 | else | ||
514 | wc = wc2; | ||
515 | /* Then proceed the next character. */ | ||
516 | rawbuf_idx += mbclen; | ||
517 | } | ||
518 | *last_wc = wc; | ||
519 | return rawbuf_idx; | ||
520 | } | ||
521 | #endif /* RE_ENABLE_I18N */ | ||
522 | |||
523 | /* Build the buffer PSTR->MBS, and apply the translation if we need. | ||
524 | This function is used in case of REG_ICASE. */ | ||
525 | |||
526 | static void | ||
527 | internal_function | ||
528 | build_upper_buffer (re_string_t *pstr) | ||
529 | { | ||
530 | Idx char_idx, end_idx; | ||
531 | end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; | ||
532 | |||
533 | for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx) | ||
534 | { | ||
535 | int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx]; | ||
536 | if (BE (pstr->trans != NULL, 0)) | ||
537 | ch = pstr->trans[ch]; | ||
538 | if (islower (ch)) | ||
539 | pstr->mbs[char_idx] = toupper (ch); | ||
540 | else | ||
541 | pstr->mbs[char_idx] = ch; | ||
542 | } | ||
543 | pstr->valid_len = char_idx; | ||
544 | pstr->valid_raw_len = char_idx; | ||
545 | } | ||
546 | |||
547 | /* Apply TRANS to the buffer in PSTR. */ | ||
548 | |||
549 | static void | ||
550 | internal_function | ||
551 | re_string_translate_buffer (re_string_t *pstr) | ||
552 | { | ||
553 | Idx buf_idx, end_idx; | ||
554 | end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; | ||
555 | |||
556 | for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx) | ||
557 | { | ||
558 | int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx]; | ||
559 | pstr->mbs[buf_idx] = pstr->trans[ch]; | ||
560 | } | ||
561 | |||
562 | pstr->valid_len = buf_idx; | ||
563 | pstr->valid_raw_len = buf_idx; | ||
564 | } | ||
565 | |||
566 | /* This function re-construct the buffers. | ||
567 | Concretely, convert to wide character in case of pstr->mb_cur_max > 1, | ||
568 | convert to upper case in case of REG_ICASE, apply translation. */ | ||
569 | |||
570 | static reg_errcode_t | ||
571 | internal_function | ||
572 | re_string_reconstruct (re_string_t *pstr, Idx idx, int eflags) | ||
573 | { | ||
574 | Idx offset; | ||
575 | |||
576 | if (BE (pstr->raw_mbs_idx <= idx, 0)) | ||
577 | offset = idx - pstr->raw_mbs_idx; | ||
578 | else | ||
579 | { | ||
580 | /* Reset buffer. */ | ||
581 | #ifdef RE_ENABLE_I18N | ||
582 | if (pstr->mb_cur_max > 1) | ||
583 | memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); | ||
584 | #endif /* RE_ENABLE_I18N */ | ||
585 | pstr->len = pstr->raw_len; | ||
586 | pstr->stop = pstr->raw_stop; | ||
587 | pstr->valid_len = 0; | ||
588 | pstr->raw_mbs_idx = 0; | ||
589 | pstr->valid_raw_len = 0; | ||
590 | pstr->offsets_needed = 0; | ||
591 | pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF | ||
592 | : CONTEXT_NEWLINE | CONTEXT_BEGBUF); | ||
593 | if (!pstr->mbs_allocated) | ||
594 | pstr->mbs = (unsigned char *) pstr->raw_mbs; | ||
595 | offset = idx; | ||
596 | } | ||
597 | |||
598 | if (BE (offset != 0, 1)) | ||
599 | { | ||
600 | /* Should the already checked characters be kept? */ | ||
601 | if (BE (offset < pstr->valid_raw_len, 1)) | ||
602 | { | ||
603 | /* Yes, move them to the front of the buffer. */ | ||
604 | #ifdef RE_ENABLE_I18N | ||
605 | if (BE (pstr->offsets_needed, 0)) | ||
606 | { | ||
607 | Idx low = 0, high = pstr->valid_len, mid; | ||
608 | do | ||
609 | { | ||
610 | mid = (high + low) / 2; | ||
611 | if (pstr->offsets[mid] > offset) | ||
612 | high = mid; | ||
613 | else if (pstr->offsets[mid] < offset) | ||
614 | low = mid + 1; | ||
615 | else | ||
616 | break; | ||
617 | } | ||
618 | while (low < high); | ||
619 | if (pstr->offsets[mid] < offset) | ||
620 | ++mid; | ||
621 | pstr->tip_context = re_string_context_at (pstr, mid - 1, | ||
622 | eflags); | ||
623 | /* This can be quite complicated, so handle specially | ||
624 | only the common and easy case where the character with | ||
625 | different length representation of lower and upper | ||
626 | case is present at or after offset. */ | ||
627 | if (pstr->valid_len > offset | ||
628 | && mid == offset && pstr->offsets[mid] == offset) | ||
629 | { | ||
630 | memmove (pstr->wcs, pstr->wcs + offset, | ||
631 | (pstr->valid_len - offset) * sizeof (wint_t)); | ||
632 | memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset); | ||
633 | pstr->valid_len -= offset; | ||
634 | pstr->valid_raw_len -= offset; | ||
635 | for (low = 0; low < pstr->valid_len; low++) | ||
636 | pstr->offsets[low] = pstr->offsets[low + offset] - offset; | ||
637 | } | ||
638 | else | ||
639 | { | ||
640 | /* Otherwise, just find out how long the partial multibyte | ||
641 | character at offset is and fill it with WEOF/255. */ | ||
642 | pstr->len = pstr->raw_len - idx + offset; | ||
643 | pstr->stop = pstr->raw_stop - idx + offset; | ||
644 | pstr->offsets_needed = 0; | ||
645 | while (mid > 0 && pstr->offsets[mid - 1] == offset) | ||
646 | --mid; | ||
647 | while (mid < pstr->valid_len) | ||
648 | if (pstr->wcs[mid] != WEOF) | ||
649 | break; | ||
650 | else | ||
651 | ++mid; | ||
652 | if (mid == pstr->valid_len) | ||
653 | pstr->valid_len = 0; | ||
654 | else | ||
655 | { | ||
656 | pstr->valid_len = pstr->offsets[mid] - offset; | ||
657 | if (pstr->valid_len) | ||
658 | { | ||
659 | for (low = 0; low < pstr->valid_len; ++low) | ||
660 | pstr->wcs[low] = WEOF; | ||
661 | memset (pstr->mbs, 255, pstr->valid_len); | ||
662 | } | ||
663 | } | ||
664 | pstr->valid_raw_len = pstr->valid_len; | ||
665 | } | ||
666 | } | ||
667 | else | ||
668 | #endif | ||
669 | { | ||
670 | pstr->tip_context = re_string_context_at (pstr, offset - 1, | ||
671 | eflags); | ||
672 | #ifdef RE_ENABLE_I18N | ||
673 | if (pstr->mb_cur_max > 1) | ||
674 | memmove (pstr->wcs, pstr->wcs + offset, | ||
675 | (pstr->valid_len - offset) * sizeof (wint_t)); | ||
676 | #endif /* RE_ENABLE_I18N */ | ||
677 | if (BE (pstr->mbs_allocated, 0)) | ||
678 | memmove (pstr->mbs, pstr->mbs + offset, | ||
679 | pstr->valid_len - offset); | ||
680 | pstr->valid_len -= offset; | ||
681 | pstr->valid_raw_len -= offset; | ||
682 | #if DEBUG | ||
683 | assert (pstr->valid_len > 0); | ||
684 | #endif | ||
685 | } | ||
686 | } | ||
687 | else | ||
688 | { | ||
689 | /* No, skip all characters until IDX. */ | ||
690 | Idx prev_valid_len = pstr->valid_len; | ||
691 | |||
692 | #ifdef RE_ENABLE_I18N | ||
693 | if (BE (pstr->offsets_needed, 0)) | ||
694 | { | ||
695 | pstr->len = pstr->raw_len - idx + offset; | ||
696 | pstr->stop = pstr->raw_stop - idx + offset; | ||
697 | pstr->offsets_needed = 0; | ||
698 | } | ||
699 | #endif | ||
700 | pstr->valid_len = 0; | ||
701 | #ifdef RE_ENABLE_I18N | ||
702 | if (pstr->mb_cur_max > 1) | ||
703 | { | ||
704 | Idx wcs_idx; | ||
705 | wint_t wc = WEOF; | ||
706 | |||
707 | if (pstr->is_utf8) | ||
708 | { | ||
709 | const unsigned char *raw, *p, *q, *end; | ||
710 | |||
711 | /* Special case UTF-8. Multi-byte chars start with any | ||
712 | byte other than 0x80 - 0xbf. */ | ||
713 | raw = pstr->raw_mbs + pstr->raw_mbs_idx; | ||
714 | end = raw + (offset - pstr->mb_cur_max); | ||
715 | if (end < pstr->raw_mbs) | ||
716 | end = pstr->raw_mbs; | ||
717 | p = raw + offset - 1; | ||
718 | #ifdef _LIBC | ||
719 | /* We know the wchar_t encoding is UCS4, so for the simple | ||
720 | case, ASCII characters, skip the conversion step. */ | ||
721 | if (isascii (*p) && BE (pstr->trans == NULL, 1)) | ||
722 | { | ||
723 | memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); | ||
724 | /* pstr->valid_len = 0; */ | ||
725 | wc = (wchar_t) *p; | ||
726 | } | ||
727 | else | ||
728 | #endif | ||
729 | for (; p >= end; --p) | ||
730 | if ((*p & 0xc0) != 0x80) | ||
731 | { | ||
732 | mbstate_t cur_state; | ||
733 | wchar_t wc2; | ||
734 | Idx mlen = raw + pstr->len - p; | ||
735 | unsigned char buf[6]; | ||
736 | size_t mbclen; | ||
737 | |||
738 | q = p; | ||
739 | if (BE (pstr->trans != NULL, 0)) | ||
740 | { | ||
741 | int i = mlen < 6 ? mlen : 6; | ||
742 | while (--i >= 0) | ||
743 | buf[i] = pstr->trans[p[i]]; | ||
744 | q = buf; | ||
745 | } | ||
746 | /* XXX Don't use mbrtowc, we know which conversion | ||
747 | to use (UTF-8 -> UCS4). */ | ||
748 | memset (&cur_state, 0, sizeof (cur_state)); | ||
749 | mbclen = mbrtowc (&wc2, (const char *) p, mlen, | ||
750 | &cur_state); | ||
751 | if (raw + offset - p <= mbclen | ||
752 | && mbclen < (size_t) -2) | ||
753 | { | ||
754 | memset (&pstr->cur_state, '\0', | ||
755 | sizeof (mbstate_t)); | ||
756 | pstr->valid_len = mbclen - (raw + offset - p); | ||
757 | wc = wc2; | ||
758 | } | ||
759 | break; | ||
760 | } | ||
761 | } | ||
762 | |||
763 | if (wc == WEOF) | ||
764 | pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx; | ||
765 | if (wc == WEOF) | ||
766 | pstr->tip_context | ||
767 | = re_string_context_at (pstr, prev_valid_len - 1, eflags); | ||
768 | else | ||
769 | pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0) | ||
770 | && IS_WIDE_WORD_CHAR (wc)) | ||
771 | ? CONTEXT_WORD | ||
772 | : ((IS_WIDE_NEWLINE (wc) | ||
773 | && pstr->newline_anchor) | ||
774 | ? CONTEXT_NEWLINE : 0)); | ||
775 | if (BE (pstr->valid_len, 0)) | ||
776 | { | ||
777 | for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx) | ||
778 | pstr->wcs[wcs_idx] = WEOF; | ||
779 | if (pstr->mbs_allocated) | ||
780 | memset (pstr->mbs, 255, pstr->valid_len); | ||
781 | } | ||
782 | pstr->valid_raw_len = pstr->valid_len; | ||
783 | } | ||
784 | else | ||
785 | #endif /* RE_ENABLE_I18N */ | ||
786 | { | ||
787 | int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1]; | ||
788 | pstr->valid_raw_len = 0; | ||
789 | if (pstr->trans) | ||
790 | c = pstr->trans[c]; | ||
791 | pstr->tip_context = (bitset_contain (pstr->word_char, c) | ||
792 | ? CONTEXT_WORD | ||
793 | : ((IS_NEWLINE (c) && pstr->newline_anchor) | ||
794 | ? CONTEXT_NEWLINE : 0)); | ||
795 | } | ||
796 | } | ||
797 | if (!BE (pstr->mbs_allocated, 0)) | ||
798 | pstr->mbs += offset; | ||
799 | } | ||
800 | pstr->raw_mbs_idx = idx; | ||
801 | pstr->len -= offset; | ||
802 | pstr->stop -= offset; | ||
803 | |||
804 | /* Then build the buffers. */ | ||
805 | #ifdef RE_ENABLE_I18N | ||
806 | if (pstr->mb_cur_max > 1) | ||
807 | { | ||
808 | if (pstr->icase) | ||
809 | { | ||
810 | reg_errcode_t ret = build_wcs_upper_buffer (pstr); | ||
811 | if (BE (ret != REG_NOERROR, 0)) | ||
812 | return ret; | ||
813 | } | ||
814 | else | ||
815 | build_wcs_buffer (pstr); | ||
816 | } | ||
817 | else | ||
818 | #endif /* RE_ENABLE_I18N */ | ||
819 | if (BE (pstr->mbs_allocated, 0)) | ||
820 | { | ||
821 | if (pstr->icase) | ||
822 | build_upper_buffer (pstr); | ||
823 | else if (pstr->trans != NULL) | ||
824 | re_string_translate_buffer (pstr); | ||
825 | } | ||
826 | else | ||
827 | pstr->valid_len = pstr->len; | ||
828 | |||
829 | pstr->cur_idx = 0; | ||
830 | return REG_NOERROR; | ||
831 | } | ||
832 | |||
833 | static unsigned char | ||
834 | internal_function __attribute ((pure)) | ||
835 | re_string_peek_byte_case (const re_string_t *pstr, Idx idx) | ||
836 | { | ||
837 | int ch; | ||
838 | Idx off; | ||
839 | |||
840 | /* Handle the common (easiest) cases first. */ | ||
841 | if (BE (!pstr->mbs_allocated, 1)) | ||
842 | return re_string_peek_byte (pstr, idx); | ||
843 | |||
844 | #ifdef RE_ENABLE_I18N | ||
845 | if (pstr->mb_cur_max > 1 | ||
846 | && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx)) | ||
847 | return re_string_peek_byte (pstr, idx); | ||
848 | #endif | ||
849 | |||
850 | off = pstr->cur_idx + idx; | ||
851 | #ifdef RE_ENABLE_I18N | ||
852 | if (pstr->offsets_needed) | ||
853 | off = pstr->offsets[off]; | ||
854 | #endif | ||
855 | |||
856 | ch = pstr->raw_mbs[pstr->raw_mbs_idx + off]; | ||
857 | |||
858 | #ifdef RE_ENABLE_I18N | ||
859 | /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I | ||
860 | this function returns CAPITAL LETTER I instead of first byte of | ||
861 | DOTLESS SMALL LETTER I. The latter would confuse the parser, | ||
862 | since peek_byte_case doesn't advance cur_idx in any way. */ | ||
863 | if (pstr->offsets_needed && !isascii (ch)) | ||
864 | return re_string_peek_byte (pstr, idx); | ||
865 | #endif | ||
866 | |||
867 | return ch; | ||
868 | } | ||
869 | |||
870 | static unsigned char | ||
871 | internal_function __attribute ((pure)) | ||
872 | re_string_fetch_byte_case (re_string_t *pstr) | ||
873 | { | ||
874 | if (BE (!pstr->mbs_allocated, 1)) | ||
875 | return re_string_fetch_byte (pstr); | ||
876 | |||
877 | #ifdef RE_ENABLE_I18N | ||
878 | if (pstr->offsets_needed) | ||
879 | { | ||
880 | Idx off; | ||
881 | int ch; | ||
882 | |||
883 | /* For tr_TR.UTF-8 [[:islower:]] there is | ||
884 | [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip | ||
885 | in that case the whole multi-byte character and return | ||
886 | the original letter. On the other side, with | ||
887 | [[: DOTLESS SMALL LETTER I return [[:I, as doing | ||
888 | anything else would complicate things too much. */ | ||
889 | |||
890 | if (!re_string_first_byte (pstr, pstr->cur_idx)) | ||
891 | return re_string_fetch_byte (pstr); | ||
892 | |||
893 | off = pstr->offsets[pstr->cur_idx]; | ||
894 | ch = pstr->raw_mbs[pstr->raw_mbs_idx + off]; | ||
895 | |||
896 | if (! isascii (ch)) | ||
897 | return re_string_fetch_byte (pstr); | ||
898 | |||
899 | re_string_skip_bytes (pstr, | ||
900 | re_string_char_size_at (pstr, pstr->cur_idx)); | ||
901 | return ch; | ||
902 | } | ||
903 | #endif | ||
904 | |||
905 | return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++]; | ||
906 | } | ||
907 | |||
908 | static void | ||
909 | internal_function | ||
910 | re_string_destruct (re_string_t *pstr) | ||
911 | { | ||
912 | #ifdef RE_ENABLE_I18N | ||
913 | re_free (pstr->wcs); | ||
914 | re_free (pstr->offsets); | ||
915 | #endif /* RE_ENABLE_I18N */ | ||
916 | if (pstr->mbs_allocated) | ||
917 | re_free (pstr->mbs); | ||
918 | } | ||
919 | |||
920 | /* Return the context at IDX in INPUT. */ | ||
921 | |||
922 | static unsigned int | ||
923 | internal_function | ||
924 | re_string_context_at (const re_string_t *input, Idx idx, int eflags) | ||
925 | { | ||
926 | int c; | ||
927 | if (BE (! REG_VALID_INDEX (idx), 0)) | ||
928 | /* In this case, we use the value stored in input->tip_context, | ||
929 | since we can't know the character in input->mbs[-1] here. */ | ||
930 | return input->tip_context; | ||
931 | if (BE (idx == input->len, 0)) | ||
932 | return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF | ||
933 | : CONTEXT_NEWLINE | CONTEXT_ENDBUF); | ||
934 | #ifdef RE_ENABLE_I18N | ||
935 | if (input->mb_cur_max > 1) | ||
936 | { | ||
937 | wint_t wc; | ||
938 | Idx wc_idx = idx; | ||
939 | while(input->wcs[wc_idx] == WEOF) | ||
940 | { | ||
941 | #ifdef DEBUG | ||
942 | /* It must not happen. */ | ||
943 | assert (REG_VALID_INDEX (wc_idx)); | ||
944 | #endif | ||
945 | --wc_idx; | ||
946 | if (! REG_VALID_INDEX (wc_idx)) | ||
947 | return input->tip_context; | ||
948 | } | ||
949 | wc = input->wcs[wc_idx]; | ||
950 | if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc)) | ||
951 | return CONTEXT_WORD; | ||
952 | return (IS_WIDE_NEWLINE (wc) && input->newline_anchor | ||
953 | ? CONTEXT_NEWLINE : 0); | ||
954 | } | ||
955 | else | ||
956 | #endif | ||
957 | { | ||
958 | c = re_string_byte_at (input, idx); | ||
959 | if (bitset_contain (input->word_char, c)) | ||
960 | return CONTEXT_WORD; | ||
961 | return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0; | ||
962 | } | ||
963 | } | ||
964 | |||
965 | /* Functions for set operation. */ | ||
966 | |||
967 | static reg_errcode_t | ||
968 | internal_function | ||
969 | re_node_set_alloc (re_node_set *set, Idx size) | ||
970 | { | ||
971 | set->alloc = size; | ||
972 | set->nelem = 0; | ||
973 | set->elems = re_malloc (Idx, size); | ||
974 | if (BE (set->elems == NULL, 0)) | ||
975 | return REG_ESPACE; | ||
976 | return REG_NOERROR; | ||
977 | } | ||
978 | |||
979 | static reg_errcode_t | ||
980 | internal_function | ||
981 | re_node_set_init_1 (re_node_set *set, Idx elem) | ||
982 | { | ||
983 | set->alloc = 1; | ||
984 | set->nelem = 1; | ||
985 | set->elems = re_malloc (Idx, 1); | ||
986 | if (BE (set->elems == NULL, 0)) | ||
987 | { | ||
988 | set->alloc = set->nelem = 0; | ||
989 | return REG_ESPACE; | ||
990 | } | ||
991 | set->elems[0] = elem; | ||
992 | return REG_NOERROR; | ||
993 | } | ||
994 | |||
995 | static reg_errcode_t | ||
996 | internal_function | ||
997 | re_node_set_init_2 (re_node_set *set, Idx elem1, Idx elem2) | ||
998 | { | ||
999 | set->alloc = 2; | ||
1000 | set->elems = re_malloc (Idx, 2); | ||
1001 | if (BE (set->elems == NULL, 0)) | ||
1002 | return REG_ESPACE; | ||
1003 | if (elem1 == elem2) | ||
1004 | { | ||
1005 | set->nelem = 1; | ||
1006 | set->elems[0] = elem1; | ||
1007 | } | ||
1008 | else | ||
1009 | { | ||
1010 | set->nelem = 2; | ||
1011 | if (elem1 < elem2) | ||
1012 | { | ||
1013 | set->elems[0] = elem1; | ||
1014 | set->elems[1] = elem2; | ||
1015 | } | ||
1016 | else | ||
1017 | { | ||
1018 | set->elems[0] = elem2; | ||
1019 | set->elems[1] = elem1; | ||
1020 | } | ||
1021 | } | ||
1022 | return REG_NOERROR; | ||
1023 | } | ||
1024 | |||
1025 | static reg_errcode_t | ||
1026 | internal_function | ||
1027 | re_node_set_init_copy (re_node_set *dest, const re_node_set *src) | ||
1028 | { | ||
1029 | dest->nelem = src->nelem; | ||
1030 | if (src->nelem > 0) | ||
1031 | { | ||
1032 | dest->alloc = dest->nelem; | ||
1033 | dest->elems = re_malloc (Idx, dest->alloc); | ||
1034 | if (BE (dest->elems == NULL, 0)) | ||
1035 | { | ||
1036 | dest->alloc = dest->nelem = 0; | ||
1037 | return REG_ESPACE; | ||
1038 | } | ||
1039 | memcpy (dest->elems, src->elems, src->nelem * sizeof (Idx)); | ||
1040 | } | ||
1041 | else | ||
1042 | re_node_set_init_empty (dest); | ||
1043 | return REG_NOERROR; | ||
1044 | } | ||
1045 | |||
1046 | /* Calculate the intersection of the sets SRC1 and SRC2. And merge it to | ||
1047 | DEST. Return value indicate the error code or REG_NOERROR if succeeded. | ||
1048 | Note: We assume dest->elems is NULL, when dest->alloc is 0. */ | ||
1049 | |||
1050 | static reg_errcode_t | ||
1051 | internal_function | ||
1052 | re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1, | ||
1053 | const re_node_set *src2) | ||
1054 | { | ||
1055 | Idx i1, i2, is, id, delta, sbase; | ||
1056 | if (src1->nelem == 0 || src2->nelem == 0) | ||
1057 | return REG_NOERROR; | ||
1058 | |||
1059 | /* We need dest->nelem + 2 * elems_in_intersection; this is a | ||
1060 | conservative estimate. */ | ||
1061 | if (src1->nelem + src2->nelem + dest->nelem > dest->alloc) | ||
1062 | { | ||
1063 | Idx new_alloc = src1->nelem + src2->nelem + dest->alloc; | ||
1064 | Idx *new_elems = re_realloc (dest->elems, Idx, new_alloc); | ||
1065 | if (BE (new_elems == NULL, 0)) | ||
1066 | return REG_ESPACE; | ||
1067 | dest->elems = new_elems; | ||
1068 | dest->alloc = new_alloc; | ||
1069 | } | ||
1070 | |||
1071 | /* Find the items in the intersection of SRC1 and SRC2, and copy | ||
1072 | into the top of DEST those that are not already in DEST itself. */ | ||
1073 | sbase = dest->nelem + src1->nelem + src2->nelem; | ||
1074 | i1 = src1->nelem - 1; | ||
1075 | i2 = src2->nelem - 1; | ||
1076 | id = dest->nelem - 1; | ||
1077 | for (;;) | ||
1078 | { | ||
1079 | if (src1->elems[i1] == src2->elems[i2]) | ||
1080 | { | ||
1081 | /* Try to find the item in DEST. Maybe we could binary search? */ | ||
1082 | while (REG_VALID_INDEX (id) && dest->elems[id] > src1->elems[i1]) | ||
1083 | --id; | ||
1084 | |||
1085 | if (! REG_VALID_INDEX (id) || dest->elems[id] != src1->elems[i1]) | ||
1086 | dest->elems[--sbase] = src1->elems[i1]; | ||
1087 | |||
1088 | if (! REG_VALID_INDEX (--i1) || ! REG_VALID_INDEX (--i2)) | ||
1089 | break; | ||
1090 | } | ||
1091 | |||
1092 | /* Lower the highest of the two items. */ | ||
1093 | else if (src1->elems[i1] < src2->elems[i2]) | ||
1094 | { | ||
1095 | if (! REG_VALID_INDEX (--i2)) | ||
1096 | break; | ||
1097 | } | ||
1098 | else | ||
1099 | { | ||
1100 | if (! REG_VALID_INDEX (--i1)) | ||
1101 | break; | ||
1102 | } | ||
1103 | } | ||
1104 | |||
1105 | id = dest->nelem - 1; | ||
1106 | is = dest->nelem + src1->nelem + src2->nelem - 1; | ||
1107 | delta = is - sbase + 1; | ||
1108 | |||
1109 | /* Now copy. When DELTA becomes zero, the remaining | ||
1110 | DEST elements are already in place; this is more or | ||
1111 | less the same loop that is in re_node_set_merge. */ | ||
1112 | dest->nelem += delta; | ||
1113 | if (delta > 0 && REG_VALID_INDEX (id)) | ||
1114 | for (;;) | ||
1115 | { | ||
1116 | if (dest->elems[is] > dest->elems[id]) | ||
1117 | { | ||
1118 | /* Copy from the top. */ | ||
1119 | dest->elems[id + delta--] = dest->elems[is--]; | ||
1120 | if (delta == 0) | ||
1121 | break; | ||
1122 | } | ||
1123 | else | ||
1124 | { | ||
1125 | /* Slide from the bottom. */ | ||
1126 | dest->elems[id + delta] = dest->elems[id]; | ||
1127 | if (! REG_VALID_INDEX (--id)) | ||
1128 | break; | ||
1129 | } | ||
1130 | } | ||
1131 | |||
1132 | /* Copy remaining SRC elements. */ | ||
1133 | memcpy (dest->elems, dest->elems + sbase, delta * sizeof (Idx)); | ||
1134 | |||
1135 | return REG_NOERROR; | ||
1136 | } | ||
1137 | |||
1138 | /* Calculate the union set of the sets SRC1 and SRC2. And store it to | ||
1139 | DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ | ||
1140 | |||
1141 | static reg_errcode_t | ||
1142 | internal_function | ||
1143 | re_node_set_init_union (re_node_set *dest, const re_node_set *src1, | ||
1144 | const re_node_set *src2) | ||
1145 | { | ||
1146 | Idx i1, i2, id; | ||
1147 | if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) | ||
1148 | { | ||
1149 | dest->alloc = src1->nelem + src2->nelem; | ||
1150 | dest->elems = re_malloc (Idx, dest->alloc); | ||
1151 | if (BE (dest->elems == NULL, 0)) | ||
1152 | return REG_ESPACE; | ||
1153 | } | ||
1154 | else | ||
1155 | { | ||
1156 | if (src1 != NULL && src1->nelem > 0) | ||
1157 | return re_node_set_init_copy (dest, src1); | ||
1158 | else if (src2 != NULL && src2->nelem > 0) | ||
1159 | return re_node_set_init_copy (dest, src2); | ||
1160 | else | ||
1161 | re_node_set_init_empty (dest); | ||
1162 | return REG_NOERROR; | ||
1163 | } | ||
1164 | for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;) | ||
1165 | { | ||
1166 | if (src1->elems[i1] > src2->elems[i2]) | ||
1167 | { | ||
1168 | dest->elems[id++] = src2->elems[i2++]; | ||
1169 | continue; | ||
1170 | } | ||
1171 | if (src1->elems[i1] == src2->elems[i2]) | ||
1172 | ++i2; | ||
1173 | dest->elems[id++] = src1->elems[i1++]; | ||
1174 | } | ||
1175 | if (i1 < src1->nelem) | ||
1176 | { | ||
1177 | memcpy (dest->elems + id, src1->elems + i1, | ||
1178 | (src1->nelem - i1) * sizeof (Idx)); | ||
1179 | id += src1->nelem - i1; | ||
1180 | } | ||
1181 | else if (i2 < src2->nelem) | ||
1182 | { | ||
1183 | memcpy (dest->elems + id, src2->elems + i2, | ||
1184 | (src2->nelem - i2) * sizeof (Idx)); | ||
1185 | id += src2->nelem - i2; | ||
1186 | } | ||
1187 | dest->nelem = id; | ||
1188 | return REG_NOERROR; | ||
1189 | } | ||
1190 | |||
1191 | /* Calculate the union set of the sets DEST and SRC. And store it to | ||
1192 | DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ | ||
1193 | |||
1194 | static reg_errcode_t | ||
1195 | internal_function | ||
1196 | re_node_set_merge (re_node_set *dest, const re_node_set *src) | ||
1197 | { | ||
1198 | Idx is, id, sbase, delta; | ||
1199 | if (src == NULL || src->nelem == 0) | ||
1200 | return REG_NOERROR; | ||
1201 | if (dest->alloc < 2 * src->nelem + dest->nelem) | ||
1202 | { | ||
1203 | Idx new_alloc = 2 * (src->nelem + dest->alloc); | ||
1204 | Idx *new_buffer = re_realloc (dest->elems, Idx, new_alloc); | ||
1205 | if (BE (new_buffer == NULL, 0)) | ||
1206 | return REG_ESPACE; | ||
1207 | dest->elems = new_buffer; | ||
1208 | dest->alloc = new_alloc; | ||
1209 | } | ||
1210 | |||
1211 | if (BE (dest->nelem == 0, 0)) | ||
1212 | { | ||
1213 | dest->nelem = src->nelem; | ||
1214 | memcpy (dest->elems, src->elems, src->nelem * sizeof (Idx)); | ||
1215 | return REG_NOERROR; | ||
1216 | } | ||
1217 | |||
1218 | /* Copy into the top of DEST the items of SRC that are not | ||
1219 | found in DEST. Maybe we could binary search in DEST? */ | ||
1220 | for (sbase = dest->nelem + 2 * src->nelem, | ||
1221 | is = src->nelem - 1, id = dest->nelem - 1; | ||
1222 | REG_VALID_INDEX (is) && REG_VALID_INDEX (id); ) | ||
1223 | { | ||
1224 | if (dest->elems[id] == src->elems[is]) | ||
1225 | is--, id--; | ||
1226 | else if (dest->elems[id] < src->elems[is]) | ||
1227 | dest->elems[--sbase] = src->elems[is--]; | ||
1228 | else /* if (dest->elems[id] > src->elems[is]) */ | ||
1229 | --id; | ||
1230 | } | ||
1231 | |||
1232 | if (REG_VALID_INDEX (is)) | ||
1233 | { | ||
1234 | /* If DEST is exhausted, the remaining items of SRC must be unique. */ | ||
1235 | sbase -= is + 1; | ||
1236 | memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (Idx)); | ||
1237 | } | ||
1238 | |||
1239 | id = dest->nelem - 1; | ||
1240 | is = dest->nelem + 2 * src->nelem - 1; | ||
1241 | delta = is - sbase + 1; | ||
1242 | if (delta == 0) | ||
1243 | return REG_NOERROR; | ||
1244 | |||
1245 | /* Now copy. When DELTA becomes zero, the remaining | ||
1246 | DEST elements are already in place. */ | ||
1247 | dest->nelem += delta; | ||
1248 | for (;;) | ||
1249 | { | ||
1250 | if (dest->elems[is] > dest->elems[id]) | ||
1251 | { | ||
1252 | /* Copy from the top. */ | ||
1253 | dest->elems[id + delta--] = dest->elems[is--]; | ||
1254 | if (delta == 0) | ||
1255 | break; | ||
1256 | } | ||
1257 | else | ||
1258 | { | ||
1259 | /* Slide from the bottom. */ | ||
1260 | dest->elems[id + delta] = dest->elems[id]; | ||
1261 | if (! REG_VALID_INDEX (--id)) | ||
1262 | { | ||
1263 | /* Copy remaining SRC elements. */ | ||
1264 | memcpy (dest->elems, dest->elems + sbase, | ||
1265 | delta * sizeof (Idx)); | ||
1266 | break; | ||
1267 | } | ||
1268 | } | ||
1269 | } | ||
1270 | |||
1271 | return REG_NOERROR; | ||
1272 | } | ||
1273 | |||
1274 | /* Insert the new element ELEM to the re_node_set* SET. | ||
1275 | SET should not already have ELEM. | ||
1276 | Return true if successful. */ | ||
1277 | |||
1278 | static bool | ||
1279 | internal_function | ||
1280 | re_node_set_insert (re_node_set *set, Idx elem) | ||
1281 | { | ||
1282 | Idx idx; | ||
1283 | /* In case the set is empty. */ | ||
1284 | if (set->alloc == 0) | ||
1285 | return BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1); | ||
1286 | |||
1287 | if (BE (set->nelem, 0) == 0) | ||
1288 | { | ||
1289 | /* We already guaranteed above that set->alloc != 0. */ | ||
1290 | set->elems[0] = elem; | ||
1291 | ++set->nelem; | ||
1292 | return true; | ||
1293 | } | ||
1294 | |||
1295 | /* Realloc if we need. */ | ||
1296 | if (set->alloc == set->nelem) | ||
1297 | { | ||
1298 | Idx *new_elems; | ||
1299 | set->alloc = set->alloc * 2; | ||
1300 | new_elems = re_realloc (set->elems, Idx, set->alloc); | ||
1301 | if (BE (new_elems == NULL, 0)) | ||
1302 | return false; | ||
1303 | set->elems = new_elems; | ||
1304 | } | ||
1305 | |||
1306 | /* Move the elements which follows the new element. Test the | ||
1307 | first element separately to skip a check in the inner loop. */ | ||
1308 | if (elem < set->elems[0]) | ||
1309 | { | ||
1310 | idx = 0; | ||
1311 | for (idx = set->nelem; idx > 0; idx--) | ||
1312 | set->elems[idx] = set->elems[idx - 1]; | ||
1313 | } | ||
1314 | else | ||
1315 | { | ||
1316 | for (idx = set->nelem; set->elems[idx - 1] > elem; idx--) | ||
1317 | set->elems[idx] = set->elems[idx - 1]; | ||
1318 | } | ||
1319 | |||
1320 | /* Insert the new element. */ | ||
1321 | set->elems[idx] = elem; | ||
1322 | ++set->nelem; | ||
1323 | return true; | ||
1324 | } | ||
1325 | |||
1326 | /* Insert the new element ELEM to the re_node_set* SET. | ||
1327 | SET should not already have any element greater than or equal to ELEM. | ||
1328 | Return true if successful. */ | ||
1329 | |||
1330 | static bool | ||
1331 | internal_function | ||
1332 | re_node_set_insert_last (re_node_set *set, Idx elem) | ||
1333 | { | ||
1334 | /* Realloc if we need. */ | ||
1335 | if (set->alloc == set->nelem) | ||
1336 | { | ||
1337 | Idx *new_elems; | ||
1338 | set->alloc = (set->alloc + 1) * 2; | ||
1339 | new_elems = re_realloc (set->elems, Idx, set->alloc); | ||
1340 | if (BE (new_elems == NULL, 0)) | ||
1341 | return false; | ||
1342 | set->elems = new_elems; | ||
1343 | } | ||
1344 | |||
1345 | /* Insert the new element. */ | ||
1346 | set->elems[set->nelem++] = elem; | ||
1347 | return true; | ||
1348 | } | ||
1349 | |||
1350 | /* Compare two node sets SET1 and SET2. | ||
1351 | Return true if SET1 and SET2 are equivalent. */ | ||
1352 | |||
1353 | static bool | ||
1354 | internal_function __attribute ((pure)) | ||
1355 | re_node_set_compare (const re_node_set *set1, const re_node_set *set2) | ||
1356 | { | ||
1357 | Idx i; | ||
1358 | if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem) | ||
1359 | return false; | ||
1360 | for (i = set1->nelem ; REG_VALID_INDEX (--i) ; ) | ||
1361 | if (set1->elems[i] != set2->elems[i]) | ||
1362 | return false; | ||
1363 | return true; | ||
1364 | } | ||
1365 | |||
1366 | /* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */ | ||
1367 | |||
1368 | static Idx | ||
1369 | internal_function __attribute ((pure)) | ||
1370 | re_node_set_contains (const re_node_set *set, Idx elem) | ||
1371 | { | ||
1372 | __re_size_t idx, right, mid; | ||
1373 | if (! REG_VALID_NONZERO_INDEX (set->nelem)) | ||
1374 | return 0; | ||
1375 | |||
1376 | /* Binary search the element. */ | ||
1377 | idx = 0; | ||
1378 | right = set->nelem - 1; | ||
1379 | while (idx < right) | ||
1380 | { | ||
1381 | mid = (idx + right) / 2; | ||
1382 | if (set->elems[mid] < elem) | ||
1383 | idx = mid + 1; | ||
1384 | else | ||
1385 | right = mid; | ||
1386 | } | ||
1387 | return set->elems[idx] == elem ? idx + 1 : 0; | ||
1388 | } | ||
1389 | |||
1390 | static void | ||
1391 | internal_function | ||
1392 | re_node_set_remove_at (re_node_set *set, Idx idx) | ||
1393 | { | ||
1394 | if (idx < 0 || idx >= set->nelem) | ||
1395 | return; | ||
1396 | --set->nelem; | ||
1397 | for (; idx < set->nelem; idx++) | ||
1398 | set->elems[idx] = set->elems[idx + 1]; | ||
1399 | } | ||
1400 | |||
1401 | |||
1402 | /* Add the token TOKEN to dfa->nodes, and return the index of the token. | ||
1403 | Or return REG_MISSING if an error occurred. */ | ||
1404 | |||
1405 | static Idx | ||
1406 | internal_function | ||
1407 | re_dfa_add_node (re_dfa_t *dfa, re_token_t token) | ||
1408 | { | ||
1409 | if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0)) | ||
1410 | { | ||
1411 | size_t new_nodes_alloc = dfa->nodes_alloc * 2; | ||
1412 | Idx *new_nexts, *new_indices; | ||
1413 | re_node_set *new_edests, *new_eclosures; | ||
1414 | re_token_t *new_nodes; | ||
1415 | size_t max_object_size = | ||
1416 | MAX (sizeof (re_token_t), | ||
1417 | MAX (sizeof (re_node_set), | ||
1418 | sizeof (Idx))); | ||
1419 | |||
1420 | /* Avoid overflows. */ | ||
1421 | if (BE (SIZE_MAX / 2 / max_object_size < dfa->nodes_alloc, 0)) | ||
1422 | return REG_MISSING; | ||
1423 | |||
1424 | new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc); | ||
1425 | if (BE (new_nodes == NULL, 0)) | ||
1426 | return REG_MISSING; | ||
1427 | dfa->nodes = new_nodes; | ||
1428 | new_nexts = re_realloc (dfa->nexts, Idx, new_nodes_alloc); | ||
1429 | new_indices = re_realloc (dfa->org_indices, Idx, new_nodes_alloc); | ||
1430 | new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc); | ||
1431 | new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc); | ||
1432 | if (BE (new_nexts == NULL || new_indices == NULL | ||
1433 | || new_edests == NULL || new_eclosures == NULL, 0)) | ||
1434 | return REG_MISSING; | ||
1435 | dfa->nexts = new_nexts; | ||
1436 | dfa->org_indices = new_indices; | ||
1437 | dfa->edests = new_edests; | ||
1438 | dfa->eclosures = new_eclosures; | ||
1439 | dfa->nodes_alloc = new_nodes_alloc; | ||
1440 | } | ||
1441 | dfa->nodes[dfa->nodes_len] = token; | ||
1442 | dfa->nodes[dfa->nodes_len].constraint = 0; | ||
1443 | #ifdef RE_ENABLE_I18N | ||
1444 | { | ||
1445 | int type = token.type; | ||
1446 | dfa->nodes[dfa->nodes_len].accept_mb = | ||
1447 | (type == OP_PERIOD && dfa->mb_cur_max > 1) || type == COMPLEX_BRACKET; | ||
1448 | } | ||
1449 | #endif | ||
1450 | dfa->nexts[dfa->nodes_len] = REG_MISSING; | ||
1451 | re_node_set_init_empty (dfa->edests + dfa->nodes_len); | ||
1452 | re_node_set_init_empty (dfa->eclosures + dfa->nodes_len); | ||
1453 | return dfa->nodes_len++; | ||
1454 | } | ||
1455 | |||
1456 | static inline re_hashval_t | ||
1457 | internal_function | ||
1458 | calc_state_hash (const re_node_set *nodes, unsigned int context) | ||
1459 | { | ||
1460 | re_hashval_t hash = nodes->nelem + context; | ||
1461 | Idx i; | ||
1462 | for (i = 0 ; i < nodes->nelem ; i++) | ||
1463 | hash += nodes->elems[i]; | ||
1464 | return hash; | ||
1465 | } | ||
1466 | |||
1467 | /* Search for the state whose node_set is equivalent to NODES. | ||
1468 | Return the pointer to the state, if we found it in the DFA. | ||
1469 | Otherwise create the new one and return it. In case of an error | ||
1470 | return NULL and set the error code in ERR. | ||
1471 | Note: - We assume NULL as the invalid state, then it is possible that | ||
1472 | return value is NULL and ERR is REG_NOERROR. | ||
1473 | - We never return non-NULL value in case of any errors, it is for | ||
1474 | optimization. */ | ||
1475 | |||
1476 | static re_dfastate_t * | ||
1477 | internal_function | ||
1478 | re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa, | ||
1479 | const re_node_set *nodes) | ||
1480 | { | ||
1481 | re_hashval_t hash; | ||
1482 | re_dfastate_t *new_state; | ||
1483 | struct re_state_table_entry *spot; | ||
1484 | Idx i; | ||
1485 | #ifdef lint | ||
1486 | /* Suppress bogus uninitialized-variable warnings. */ | ||
1487 | *err = REG_NOERROR; | ||
1488 | #endif | ||
1489 | if (BE (nodes->nelem == 0, 0)) | ||
1490 | { | ||
1491 | *err = REG_NOERROR; | ||
1492 | return NULL; | ||
1493 | } | ||
1494 | hash = calc_state_hash (nodes, 0); | ||
1495 | spot = dfa->state_table + (hash & dfa->state_hash_mask); | ||
1496 | |||
1497 | for (i = 0 ; i < spot->num ; i++) | ||
1498 | { | ||
1499 | re_dfastate_t *state = spot->array[i]; | ||
1500 | if (hash != state->hash) | ||
1501 | continue; | ||
1502 | if (re_node_set_compare (&state->nodes, nodes)) | ||
1503 | return state; | ||
1504 | } | ||
1505 | |||
1506 | /* There are no appropriate state in the dfa, create the new one. */ | ||
1507 | new_state = create_ci_newstate (dfa, nodes, hash); | ||
1508 | if (BE (new_state == NULL, 0)) | ||
1509 | *err = REG_ESPACE; | ||
1510 | |||
1511 | return new_state; | ||
1512 | } | ||
1513 | |||
1514 | /* Search for the state whose node_set is equivalent to NODES and | ||
1515 | whose context is equivalent to CONTEXT. | ||
1516 | Return the pointer to the state, if we found it in the DFA. | ||
1517 | Otherwise create the new one and return it. In case of an error | ||
1518 | return NULL and set the error code in ERR. | ||
1519 | Note: - We assume NULL as the invalid state, then it is possible that | ||
1520 | return value is NULL and ERR is REG_NOERROR. | ||
1521 | - We never return non-NULL value in case of any errors, it is for | ||
1522 | optimization. */ | ||
1523 | |||
1524 | static re_dfastate_t * | ||
1525 | internal_function | ||
1526 | re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa, | ||
1527 | const re_node_set *nodes, unsigned int context) | ||
1528 | { | ||
1529 | re_hashval_t hash; | ||
1530 | re_dfastate_t *new_state; | ||
1531 | struct re_state_table_entry *spot; | ||
1532 | Idx i; | ||
1533 | #ifdef lint | ||
1534 | /* Suppress bogus uninitialized-variable warnings. */ | ||
1535 | *err = REG_NOERROR; | ||
1536 | #endif | ||
1537 | if (nodes->nelem == 0) | ||
1538 | { | ||
1539 | *err = REG_NOERROR; | ||
1540 | return NULL; | ||
1541 | } | ||
1542 | hash = calc_state_hash (nodes, context); | ||
1543 | spot = dfa->state_table + (hash & dfa->state_hash_mask); | ||
1544 | |||
1545 | for (i = 0 ; i < spot->num ; i++) | ||
1546 | { | ||
1547 | re_dfastate_t *state = spot->array[i]; | ||
1548 | if (state->hash == hash | ||
1549 | && state->context == context | ||
1550 | && re_node_set_compare (state->entrance_nodes, nodes)) | ||
1551 | return state; | ||
1552 | } | ||
1553 | /* There are no appropriate state in `dfa', create the new one. */ | ||
1554 | new_state = create_cd_newstate (dfa, nodes, context, hash); | ||
1555 | if (BE (new_state == NULL, 0)) | ||
1556 | *err = REG_ESPACE; | ||
1557 | |||
1558 | return new_state; | ||
1559 | } | ||
1560 | |||
1561 | /* Finish initialization of the new state NEWSTATE, and using its hash value | ||
1562 | HASH put in the appropriate bucket of DFA's state table. Return value | ||
1563 | indicates the error code if failed. */ | ||
1564 | |||
1565 | static reg_errcode_t | ||
1566 | register_state (const re_dfa_t *dfa, re_dfastate_t *newstate, | ||
1567 | re_hashval_t hash) | ||
1568 | { | ||
1569 | struct re_state_table_entry *spot; | ||
1570 | reg_errcode_t err; | ||
1571 | Idx i; | ||
1572 | |||
1573 | newstate->hash = hash; | ||
1574 | err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem); | ||
1575 | if (BE (err != REG_NOERROR, 0)) | ||
1576 | return REG_ESPACE; | ||
1577 | for (i = 0; i < newstate->nodes.nelem; i++) | ||
1578 | { | ||
1579 | Idx elem = newstate->nodes.elems[i]; | ||
1580 | if (!IS_EPSILON_NODE (dfa->nodes[elem].type)) | ||
1581 | if (BE (! re_node_set_insert_last (&newstate->non_eps_nodes, elem), 0)) | ||
1582 | return REG_ESPACE; | ||
1583 | } | ||
1584 | |||
1585 | spot = dfa->state_table + (hash & dfa->state_hash_mask); | ||
1586 | if (BE (spot->alloc <= spot->num, 0)) | ||
1587 | { | ||
1588 | Idx new_alloc = 2 * spot->num + 2; | ||
1589 | re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *, | ||
1590 | new_alloc); | ||
1591 | if (BE (new_array == NULL, 0)) | ||
1592 | return REG_ESPACE; | ||
1593 | spot->array = new_array; | ||
1594 | spot->alloc = new_alloc; | ||
1595 | } | ||
1596 | spot->array[spot->num++] = newstate; | ||
1597 | return REG_NOERROR; | ||
1598 | } | ||
1599 | |||
1600 | static void | ||
1601 | free_state (re_dfastate_t *state) | ||
1602 | { | ||
1603 | re_node_set_free (&state->non_eps_nodes); | ||
1604 | re_node_set_free (&state->inveclosure); | ||
1605 | if (state->entrance_nodes != &state->nodes) | ||
1606 | { | ||
1607 | re_node_set_free (state->entrance_nodes); | ||
1608 | re_free (state->entrance_nodes); | ||
1609 | } | ||
1610 | re_node_set_free (&state->nodes); | ||
1611 | re_free (state->word_trtable); | ||
1612 | re_free (state->trtable); | ||
1613 | re_free (state); | ||
1614 | } | ||
1615 | |||
1616 | /* Create the new state which is independ of contexts. | ||
1617 | Return the new state if succeeded, otherwise return NULL. */ | ||
1618 | |||
1619 | static re_dfastate_t * | ||
1620 | internal_function | ||
1621 | create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes, | ||
1622 | re_hashval_t hash) | ||
1623 | { | ||
1624 | Idx i; | ||
1625 | reg_errcode_t err; | ||
1626 | re_dfastate_t *newstate; | ||
1627 | |||
1628 | newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); | ||
1629 | if (BE (newstate == NULL, 0)) | ||
1630 | return NULL; | ||
1631 | err = re_node_set_init_copy (&newstate->nodes, nodes); | ||
1632 | if (BE (err != REG_NOERROR, 0)) | ||
1633 | { | ||
1634 | re_free (newstate); | ||
1635 | return NULL; | ||
1636 | } | ||
1637 | |||
1638 | newstate->entrance_nodes = &newstate->nodes; | ||
1639 | for (i = 0 ; i < nodes->nelem ; i++) | ||
1640 | { | ||
1641 | re_token_t *node = dfa->nodes + nodes->elems[i]; | ||
1642 | re_token_type_t type = node->type; | ||
1643 | if (type == CHARACTER && !node->constraint) | ||
1644 | continue; | ||
1645 | #ifdef RE_ENABLE_I18N | ||
1646 | newstate->accept_mb |= node->accept_mb; | ||
1647 | #endif /* RE_ENABLE_I18N */ | ||
1648 | |||
1649 | /* If the state has the halt node, the state is a halt state. */ | ||
1650 | if (type == END_OF_RE) | ||
1651 | newstate->halt = 1; | ||
1652 | else if (type == OP_BACK_REF) | ||
1653 | newstate->has_backref = 1; | ||
1654 | else if (type == ANCHOR || node->constraint) | ||
1655 | newstate->has_constraint = 1; | ||
1656 | } | ||
1657 | err = register_state (dfa, newstate, hash); | ||
1658 | if (BE (err != REG_NOERROR, 0)) | ||
1659 | { | ||
1660 | free_state (newstate); | ||
1661 | newstate = NULL; | ||
1662 | } | ||
1663 | return newstate; | ||
1664 | } | ||
1665 | |||
1666 | /* Create the new state which is depend on the context CONTEXT. | ||
1667 | Return the new state if succeeded, otherwise return NULL. */ | ||
1668 | |||
1669 | static re_dfastate_t * | ||
1670 | internal_function | ||
1671 | create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes, | ||
1672 | unsigned int context, re_hashval_t hash) | ||
1673 | { | ||
1674 | Idx i, nctx_nodes = 0; | ||
1675 | reg_errcode_t err; | ||
1676 | re_dfastate_t *newstate; | ||
1677 | |||
1678 | newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); | ||
1679 | if (BE (newstate == NULL, 0)) | ||
1680 | return NULL; | ||
1681 | err = re_node_set_init_copy (&newstate->nodes, nodes); | ||
1682 | if (BE (err != REG_NOERROR, 0)) | ||
1683 | { | ||
1684 | re_free (newstate); | ||
1685 | return NULL; | ||
1686 | } | ||
1687 | |||
1688 | newstate->context = context; | ||
1689 | newstate->entrance_nodes = &newstate->nodes; | ||
1690 | |||
1691 | for (i = 0 ; i < nodes->nelem ; i++) | ||
1692 | { | ||
1693 | unsigned int constraint = 0; | ||
1694 | re_token_t *node = dfa->nodes + nodes->elems[i]; | ||
1695 | re_token_type_t type = node->type; | ||
1696 | if (node->constraint) | ||
1697 | constraint = node->constraint; | ||
1698 | |||
1699 | if (type == CHARACTER && !constraint) | ||
1700 | continue; | ||
1701 | #ifdef RE_ENABLE_I18N | ||
1702 | newstate->accept_mb |= node->accept_mb; | ||
1703 | #endif /* RE_ENABLE_I18N */ | ||
1704 | |||
1705 | /* If the state has the halt node, the state is a halt state. */ | ||
1706 | if (type == END_OF_RE) | ||
1707 | newstate->halt = 1; | ||
1708 | else if (type == OP_BACK_REF) | ||
1709 | newstate->has_backref = 1; | ||
1710 | else if (type == ANCHOR) | ||
1711 | constraint = node->opr.ctx_type; | ||
1712 | |||
1713 | if (constraint) | ||
1714 | { | ||
1715 | if (newstate->entrance_nodes == &newstate->nodes) | ||
1716 | { | ||
1717 | newstate->entrance_nodes = re_malloc (re_node_set, 1); | ||
1718 | if (BE (newstate->entrance_nodes == NULL, 0)) | ||
1719 | { | ||
1720 | free_state (newstate); | ||
1721 | return NULL; | ||
1722 | } | ||
1723 | re_node_set_init_copy (newstate->entrance_nodes, nodes); | ||
1724 | nctx_nodes = 0; | ||
1725 | newstate->has_constraint = 1; | ||
1726 | } | ||
1727 | |||
1728 | if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context)) | ||
1729 | { | ||
1730 | re_node_set_remove_at (&newstate->nodes, i - nctx_nodes); | ||
1731 | ++nctx_nodes; | ||
1732 | } | ||
1733 | } | ||
1734 | } | ||
1735 | err = register_state (dfa, newstate, hash); | ||
1736 | if (BE (err != REG_NOERROR, 0)) | ||
1737 | { | ||
1738 | free_state (newstate); | ||
1739 | newstate = NULL; | ||
1740 | } | ||
1741 | return newstate; | ||
1742 | } | ||
diff --git a/gl/regex_internal.h b/gl/regex_internal.h new file mode 100644 index 00000000..b0f7e657 --- /dev/null +++ b/gl/regex_internal.h | |||
@@ -0,0 +1,862 @@ | |||
1 | /* Extended regular expression matching and search library. | ||
2 | Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. | ||
3 | This file is part of the GNU C Library. | ||
4 | Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License along | ||
17 | with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #ifndef _REGEX_INTERNAL_H | ||
21 | #define _REGEX_INTERNAL_H 1 | ||
22 | |||
23 | #include <assert.h> | ||
24 | #include <ctype.h> | ||
25 | #include <stdbool.h> | ||
26 | #include <stdio.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <string.h> | ||
29 | |||
30 | #ifndef _LIBC | ||
31 | # include "strcase.h" | ||
32 | #endif | ||
33 | |||
34 | #if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC | ||
35 | # include <langinfo.h> | ||
36 | #endif | ||
37 | #if defined HAVE_LOCALE_H || defined _LIBC | ||
38 | # include <locale.h> | ||
39 | #endif | ||
40 | |||
41 | #include <wchar.h> | ||
42 | #include <wctype.h> | ||
43 | #include <stdint.h> | ||
44 | #if defined _LIBC | ||
45 | # include <bits/libc-lock.h> | ||
46 | #else | ||
47 | # define __libc_lock_init(NAME) do { } while (0) | ||
48 | # define __libc_lock_lock(NAME) do { } while (0) | ||
49 | # define __libc_lock_unlock(NAME) do { } while (0) | ||
50 | #endif | ||
51 | |||
52 | /* In case that the system doesn't have isblank(). */ | ||
53 | #if !defined _LIBC && !HAVE_DECL_ISBLANK && !defined isblank | ||
54 | # define isblank(ch) ((ch) == ' ' || (ch) == '\t') | ||
55 | #endif | ||
56 | |||
57 | #ifdef _LIBC | ||
58 | # ifndef _RE_DEFINE_LOCALE_FUNCTIONS | ||
59 | # define _RE_DEFINE_LOCALE_FUNCTIONS 1 | ||
60 | # include <locale/localeinfo.h> | ||
61 | # include <locale/elem-hash.h> | ||
62 | # include <locale/coll-lookup.h> | ||
63 | # endif | ||
64 | #endif | ||
65 | |||
66 | /* This is for other GNU distributions with internationalized messages. */ | ||
67 | #if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC | ||
68 | # include <libintl.h> | ||
69 | # ifdef _LIBC | ||
70 | # undef gettext | ||
71 | # define gettext(msgid) \ | ||
72 | INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES) | ||
73 | # endif | ||
74 | #else | ||
75 | # define gettext(msgid) (msgid) | ||
76 | #endif | ||
77 | |||
78 | #ifndef gettext_noop | ||
79 | /* This define is so xgettext can find the internationalizable | ||
80 | strings. */ | ||
81 | # define gettext_noop(String) String | ||
82 | #endif | ||
83 | |||
84 | /* For loser systems without the definition. */ | ||
85 | #ifndef SIZE_MAX | ||
86 | # define SIZE_MAX ((size_t) -1) | ||
87 | #endif | ||
88 | |||
89 | #if (defined MB_CUR_MAX && HAVE_LOCALE_H && HAVE_WCTYPE_H && HAVE_ISWCTYPE && HAVE_WCRTOMB && HAVE_MBRTOWC && HAVE_WCSCOLL) || _LIBC | ||
90 | # define RE_ENABLE_I18N | ||
91 | #endif | ||
92 | |||
93 | #if __GNUC__ >= 3 | ||
94 | # define BE(expr, val) __builtin_expect (expr, val) | ||
95 | #else | ||
96 | # define BE(expr, val) (expr) | ||
97 | # ifdef _LIBC | ||
98 | # define inline | ||
99 | # endif | ||
100 | #endif | ||
101 | |||
102 | /* Number of ASCII characters. */ | ||
103 | #define ASCII_CHARS 0x80 | ||
104 | |||
105 | /* Number of single byte characters. */ | ||
106 | #define SBC_MAX (UCHAR_MAX + 1) | ||
107 | |||
108 | #define COLL_ELEM_LEN_MAX 8 | ||
109 | |||
110 | /* The character which represents newline. */ | ||
111 | #define NEWLINE_CHAR '\n' | ||
112 | #define WIDE_NEWLINE_CHAR L'\n' | ||
113 | |||
114 | /* Rename to standard API for using out of glibc. */ | ||
115 | #ifndef _LIBC | ||
116 | # define __wctype wctype | ||
117 | # define __iswctype iswctype | ||
118 | # define __btowc btowc | ||
119 | # ifndef __mempcpy | ||
120 | # define __mempcpy mempcpy | ||
121 | # endif | ||
122 | # define __wcrtomb wcrtomb | ||
123 | # define __regfree regfree | ||
124 | # define attribute_hidden | ||
125 | #endif /* not _LIBC */ | ||
126 | |||
127 | #if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) | ||
128 | # define __attribute(arg) __attribute__ (arg) | ||
129 | #else | ||
130 | # define __attribute(arg) | ||
131 | #endif | ||
132 | |||
133 | typedef __re_idx_t Idx; | ||
134 | |||
135 | /* Special return value for failure to match. */ | ||
136 | #define REG_MISSING ((Idx) -1) | ||
137 | |||
138 | /* Special return value for internal error. */ | ||
139 | #define REG_ERROR ((Idx) -2) | ||
140 | |||
141 | /* Test whether N is a valid index, and is not one of the above. */ | ||
142 | #ifdef _REGEX_LARGE_OFFSETS | ||
143 | # define REG_VALID_INDEX(n) ((Idx) (n) < REG_ERROR) | ||
144 | #else | ||
145 | # define REG_VALID_INDEX(n) (0 <= (n)) | ||
146 | #endif | ||
147 | |||
148 | /* Test whether N is a valid nonzero index. */ | ||
149 | #ifdef _REGEX_LARGE_OFFSETS | ||
150 | # define REG_VALID_NONZERO_INDEX(n) ((Idx) ((n) - 1) < (Idx) (REG_ERROR - 1)) | ||
151 | #else | ||
152 | # define REG_VALID_NONZERO_INDEX(n) (0 < (n)) | ||
153 | #endif | ||
154 | |||
155 | /* A hash value, suitable for computing hash tables. */ | ||
156 | typedef __re_size_t re_hashval_t; | ||
157 | |||
158 | /* An integer used to represent a set of bits. It must be unsigned, | ||
159 | and must be at least as wide as unsigned int. */ | ||
160 | typedef unsigned long int bitset_word_t; | ||
161 | /* All bits set in a bitset_word_t. */ | ||
162 | #define BITSET_WORD_MAX ULONG_MAX | ||
163 | |||
164 | /* Number of bits in a bitset_word_t. For portability to hosts with | ||
165 | padding bits, do not use '(sizeof (bitset_word_t) * CHAR_BIT)'; | ||
166 | instead, deduce it directly from BITSET_WORD_MAX. Avoid | ||
167 | greater-than-32-bit integers and unconditional shifts by more than | ||
168 | 31 bits, as they're not portable. */ | ||
169 | #if BITSET_WORD_MAX == 0xffffffff | ||
170 | # define BITSET_WORD_BITS 32 | ||
171 | #elif BITSET_WORD_MAX >> 31 >> 5 == 1 | ||
172 | # define BITSET_WORD_BITS 36 | ||
173 | #elif BITSET_WORD_MAX >> 31 >> 16 == 1 | ||
174 | # define BITSET_WORD_BITS 48 | ||
175 | #elif BITSET_WORD_MAX >> 31 >> 28 == 1 | ||
176 | # define BITSET_WORD_BITS 60 | ||
177 | #elif BITSET_WORD_MAX >> 31 >> 31 >> 1 == 1 | ||
178 | # define BITSET_WORD_BITS 64 | ||
179 | #elif BITSET_WORD_MAX >> 31 >> 31 >> 9 == 1 | ||
180 | # define BITSET_WORD_BITS 72 | ||
181 | #elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 3 == 1 | ||
182 | # define BITSET_WORD_BITS 128 | ||
183 | #elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 == 1 | ||
184 | # define BITSET_WORD_BITS 256 | ||
185 | #elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 > 1 | ||
186 | # define BITSET_WORD_BITS 257 /* any value > SBC_MAX will do here */ | ||
187 | # if BITSET_WORD_BITS <= SBC_MAX | ||
188 | # error "Invalid SBC_MAX" | ||
189 | # endif | ||
190 | #elif BITSET_WORD_MAX == (0xffffffff + 2) * 0xffffffff | ||
191 | /* Work around a bug in 64-bit PGC (before version 6.1-2), where the | ||
192 | preprocessor mishandles large unsigned values as if they were signed. */ | ||
193 | # define BITSET_WORD_BITS 64 | ||
194 | #else | ||
195 | # error "Add case for new bitset_word_t size" | ||
196 | #endif | ||
197 | |||
198 | /* Number of bitset_word_t values in a bitset_t. */ | ||
199 | #define BITSET_WORDS ((SBC_MAX + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS) | ||
200 | |||
201 | typedef bitset_word_t bitset_t[BITSET_WORDS]; | ||
202 | typedef bitset_word_t *re_bitset_ptr_t; | ||
203 | typedef const bitset_word_t *re_const_bitset_ptr_t; | ||
204 | |||
205 | #define PREV_WORD_CONSTRAINT 0x0001 | ||
206 | #define PREV_NOTWORD_CONSTRAINT 0x0002 | ||
207 | #define NEXT_WORD_CONSTRAINT 0x0004 | ||
208 | #define NEXT_NOTWORD_CONSTRAINT 0x0008 | ||
209 | #define PREV_NEWLINE_CONSTRAINT 0x0010 | ||
210 | #define NEXT_NEWLINE_CONSTRAINT 0x0020 | ||
211 | #define PREV_BEGBUF_CONSTRAINT 0x0040 | ||
212 | #define NEXT_ENDBUF_CONSTRAINT 0x0080 | ||
213 | #define WORD_DELIM_CONSTRAINT 0x0100 | ||
214 | #define NOT_WORD_DELIM_CONSTRAINT 0x0200 | ||
215 | |||
216 | typedef enum | ||
217 | { | ||
218 | INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, | ||
219 | WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, | ||
220 | WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, | ||
221 | INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, | ||
222 | LINE_FIRST = PREV_NEWLINE_CONSTRAINT, | ||
223 | LINE_LAST = NEXT_NEWLINE_CONSTRAINT, | ||
224 | BUF_FIRST = PREV_BEGBUF_CONSTRAINT, | ||
225 | BUF_LAST = NEXT_ENDBUF_CONSTRAINT, | ||
226 | WORD_DELIM = WORD_DELIM_CONSTRAINT, | ||
227 | NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT | ||
228 | } re_context_type; | ||
229 | |||
230 | typedef struct | ||
231 | { | ||
232 | Idx alloc; | ||
233 | Idx nelem; | ||
234 | Idx *elems; | ||
235 | } re_node_set; | ||
236 | |||
237 | typedef enum | ||
238 | { | ||
239 | NON_TYPE = 0, | ||
240 | |||
241 | /* Node type, These are used by token, node, tree. */ | ||
242 | CHARACTER = 1, | ||
243 | END_OF_RE = 2, | ||
244 | SIMPLE_BRACKET = 3, | ||
245 | OP_BACK_REF = 4, | ||
246 | OP_PERIOD = 5, | ||
247 | #ifdef RE_ENABLE_I18N | ||
248 | COMPLEX_BRACKET = 6, | ||
249 | OP_UTF8_PERIOD = 7, | ||
250 | #endif /* RE_ENABLE_I18N */ | ||
251 | |||
252 | /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used | ||
253 | when the debugger shows values of this enum type. */ | ||
254 | #define EPSILON_BIT 8 | ||
255 | OP_OPEN_SUBEXP = EPSILON_BIT | 0, | ||
256 | OP_CLOSE_SUBEXP = EPSILON_BIT | 1, | ||
257 | OP_ALT = EPSILON_BIT | 2, | ||
258 | OP_DUP_ASTERISK = EPSILON_BIT | 3, | ||
259 | ANCHOR = EPSILON_BIT | 4, | ||
260 | |||
261 | /* Tree type, these are used only by tree. */ | ||
262 | CONCAT = 16, | ||
263 | SUBEXP = 17, | ||
264 | |||
265 | /* Token type, these are used only by token. */ | ||
266 | OP_DUP_PLUS = 18, | ||
267 | OP_DUP_QUESTION, | ||
268 | OP_OPEN_BRACKET, | ||
269 | OP_CLOSE_BRACKET, | ||
270 | OP_CHARSET_RANGE, | ||
271 | OP_OPEN_DUP_NUM, | ||
272 | OP_CLOSE_DUP_NUM, | ||
273 | OP_NON_MATCH_LIST, | ||
274 | OP_OPEN_COLL_ELEM, | ||
275 | OP_CLOSE_COLL_ELEM, | ||
276 | OP_OPEN_EQUIV_CLASS, | ||
277 | OP_CLOSE_EQUIV_CLASS, | ||
278 | OP_OPEN_CHAR_CLASS, | ||
279 | OP_CLOSE_CHAR_CLASS, | ||
280 | OP_WORD, | ||
281 | OP_NOTWORD, | ||
282 | OP_SPACE, | ||
283 | OP_NOTSPACE, | ||
284 | BACK_SLASH | ||
285 | |||
286 | } re_token_type_t; | ||
287 | |||
288 | #ifdef RE_ENABLE_I18N | ||
289 | typedef struct | ||
290 | { | ||
291 | /* Multibyte characters. */ | ||
292 | wchar_t *mbchars; | ||
293 | |||
294 | /* Collating symbols. */ | ||
295 | # ifdef _LIBC | ||
296 | int32_t *coll_syms; | ||
297 | # endif | ||
298 | |||
299 | /* Equivalence classes. */ | ||
300 | # ifdef _LIBC | ||
301 | int32_t *equiv_classes; | ||
302 | # endif | ||
303 | |||
304 | /* Range expressions. */ | ||
305 | # ifdef _LIBC | ||
306 | uint32_t *range_starts; | ||
307 | uint32_t *range_ends; | ||
308 | # else /* not _LIBC */ | ||
309 | wchar_t *range_starts; | ||
310 | wchar_t *range_ends; | ||
311 | # endif /* not _LIBC */ | ||
312 | |||
313 | /* Character classes. */ | ||
314 | wctype_t *char_classes; | ||
315 | |||
316 | /* If this character set is the non-matching list. */ | ||
317 | unsigned int non_match : 1; | ||
318 | |||
319 | /* # of multibyte characters. */ | ||
320 | Idx nmbchars; | ||
321 | |||
322 | /* # of collating symbols. */ | ||
323 | Idx ncoll_syms; | ||
324 | |||
325 | /* # of equivalence classes. */ | ||
326 | Idx nequiv_classes; | ||
327 | |||
328 | /* # of range expressions. */ | ||
329 | Idx nranges; | ||
330 | |||
331 | /* # of character classes. */ | ||
332 | Idx nchar_classes; | ||
333 | } re_charset_t; | ||
334 | #endif /* RE_ENABLE_I18N */ | ||
335 | |||
336 | typedef struct | ||
337 | { | ||
338 | union | ||
339 | { | ||
340 | unsigned char c; /* for CHARACTER */ | ||
341 | re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */ | ||
342 | #ifdef RE_ENABLE_I18N | ||
343 | re_charset_t *mbcset; /* for COMPLEX_BRACKET */ | ||
344 | #endif /* RE_ENABLE_I18N */ | ||
345 | Idx idx; /* for BACK_REF */ | ||
346 | re_context_type ctx_type; /* for ANCHOR */ | ||
347 | } opr; | ||
348 | #if __GNUC__ >= 2 && !__STRICT_ANSI__ | ||
349 | re_token_type_t type : 8; | ||
350 | #else | ||
351 | re_token_type_t type; | ||
352 | #endif | ||
353 | unsigned int constraint : 10; /* context constraint */ | ||
354 | unsigned int duplicated : 1; | ||
355 | unsigned int opt_subexp : 1; | ||
356 | #ifdef RE_ENABLE_I18N | ||
357 | unsigned int accept_mb : 1; | ||
358 | /* These 2 bits can be moved into the union if needed (e.g. if running out | ||
359 | of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */ | ||
360 | unsigned int mb_partial : 1; | ||
361 | #endif | ||
362 | unsigned int word_char : 1; | ||
363 | } re_token_t; | ||
364 | |||
365 | #define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT) | ||
366 | |||
367 | struct re_string_t | ||
368 | { | ||
369 | /* Indicate the raw buffer which is the original string passed as an | ||
370 | argument of regexec(), re_search(), etc.. */ | ||
371 | const unsigned char *raw_mbs; | ||
372 | /* Store the multibyte string. In case of "case insensitive mode" like | ||
373 | REG_ICASE, upper cases of the string are stored, otherwise MBS points | ||
374 | the same address that RAW_MBS points. */ | ||
375 | unsigned char *mbs; | ||
376 | #ifdef RE_ENABLE_I18N | ||
377 | /* Store the wide character string which is corresponding to MBS. */ | ||
378 | wint_t *wcs; | ||
379 | Idx *offsets; | ||
380 | mbstate_t cur_state; | ||
381 | #endif | ||
382 | /* Index in RAW_MBS. Each character mbs[i] corresponds to | ||
383 | raw_mbs[raw_mbs_idx + i]. */ | ||
384 | Idx raw_mbs_idx; | ||
385 | /* The length of the valid characters in the buffers. */ | ||
386 | Idx valid_len; | ||
387 | /* The corresponding number of bytes in raw_mbs array. */ | ||
388 | Idx valid_raw_len; | ||
389 | /* The length of the buffers MBS and WCS. */ | ||
390 | Idx bufs_len; | ||
391 | /* The index in MBS, which is updated by re_string_fetch_byte. */ | ||
392 | Idx cur_idx; | ||
393 | /* length of RAW_MBS array. */ | ||
394 | Idx raw_len; | ||
395 | /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */ | ||
396 | Idx len; | ||
397 | /* End of the buffer may be shorter than its length in the cases such | ||
398 | as re_match_2, re_search_2. Then, we use STOP for end of the buffer | ||
399 | instead of LEN. */ | ||
400 | Idx raw_stop; | ||
401 | /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */ | ||
402 | Idx stop; | ||
403 | |||
404 | /* The context of mbs[0]. We store the context independently, since | ||
405 | the context of mbs[0] may be different from raw_mbs[0], which is | ||
406 | the beginning of the input string. */ | ||
407 | unsigned int tip_context; | ||
408 | /* The translation passed as a part of an argument of re_compile_pattern. */ | ||
409 | RE_TRANSLATE_TYPE trans; | ||
410 | /* Copy of re_dfa_t's word_char. */ | ||
411 | re_const_bitset_ptr_t word_char; | ||
412 | /* true if REG_ICASE. */ | ||
413 | unsigned char icase; | ||
414 | unsigned char is_utf8; | ||
415 | unsigned char map_notascii; | ||
416 | unsigned char mbs_allocated; | ||
417 | unsigned char offsets_needed; | ||
418 | unsigned char newline_anchor; | ||
419 | unsigned char word_ops_used; | ||
420 | int mb_cur_max; | ||
421 | }; | ||
422 | typedef struct re_string_t re_string_t; | ||
423 | |||
424 | |||
425 | struct re_dfa_t; | ||
426 | typedef struct re_dfa_t re_dfa_t; | ||
427 | |||
428 | #ifndef _LIBC | ||
429 | # ifdef __i386__ | ||
430 | # define internal_function __attribute ((regparm (3), stdcall)) | ||
431 | # else | ||
432 | # define internal_function | ||
433 | # endif | ||
434 | #endif | ||
435 | |||
436 | static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr, | ||
437 | Idx new_buf_len) | ||
438 | internal_function; | ||
439 | #ifdef RE_ENABLE_I18N | ||
440 | static void build_wcs_buffer (re_string_t *pstr) internal_function; | ||
441 | static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr) | ||
442 | internal_function; | ||
443 | #endif /* RE_ENABLE_I18N */ | ||
444 | static void build_upper_buffer (re_string_t *pstr) internal_function; | ||
445 | static void re_string_translate_buffer (re_string_t *pstr) internal_function; | ||
446 | static unsigned int re_string_context_at (const re_string_t *input, Idx idx, | ||
447 | int eflags) | ||
448 | internal_function __attribute ((pure)); | ||
449 | #define re_string_peek_byte(pstr, offset) \ | ||
450 | ((pstr)->mbs[(pstr)->cur_idx + offset]) | ||
451 | #define re_string_fetch_byte(pstr) \ | ||
452 | ((pstr)->mbs[(pstr)->cur_idx++]) | ||
453 | #define re_string_first_byte(pstr, idx) \ | ||
454 | ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF) | ||
455 | #define re_string_is_single_byte_char(pstr, idx) \ | ||
456 | ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \ | ||
457 | || (pstr)->wcs[(idx) + 1] != WEOF)) | ||
458 | #define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx) | ||
459 | #define re_string_cur_idx(pstr) ((pstr)->cur_idx) | ||
460 | #define re_string_get_buffer(pstr) ((pstr)->mbs) | ||
461 | #define re_string_length(pstr) ((pstr)->len) | ||
462 | #define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx]) | ||
463 | #define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) | ||
464 | #define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) | ||
465 | |||
466 | #include <alloca.h> | ||
467 | |||
468 | #ifndef _LIBC | ||
469 | # if HAVE_ALLOCA | ||
470 | /* The OS usually guarantees only one guard page at the bottom of the stack, | ||
471 | and a page size can be as small as 4096 bytes. So we cannot safely | ||
472 | allocate anything larger than 4096 bytes. Also care for the possibility | ||
473 | of a few compiler-allocated temporary stack slots. */ | ||
474 | # define __libc_use_alloca(n) ((n) < 4032) | ||
475 | # else | ||
476 | /* alloca is implemented with malloc, so just use malloc. */ | ||
477 | # define __libc_use_alloca(n) 0 | ||
478 | # endif | ||
479 | #endif | ||
480 | |||
481 | #ifndef MAX | ||
482 | # define MAX(a,b) ((a) < (b) ? (b) : (a)) | ||
483 | #endif | ||
484 | |||
485 | #define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) | ||
486 | #define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t))) | ||
487 | #define re_free(p) free (p) | ||
488 | |||
489 | struct bin_tree_t | ||
490 | { | ||
491 | struct bin_tree_t *parent; | ||
492 | struct bin_tree_t *left; | ||
493 | struct bin_tree_t *right; | ||
494 | struct bin_tree_t *first; | ||
495 | struct bin_tree_t *next; | ||
496 | |||
497 | re_token_t token; | ||
498 | |||
499 | /* `node_idx' is the index in dfa->nodes, if `type' == 0. | ||
500 | Otherwise `type' indicate the type of this node. */ | ||
501 | Idx node_idx; | ||
502 | }; | ||
503 | typedef struct bin_tree_t bin_tree_t; | ||
504 | |||
505 | #define BIN_TREE_STORAGE_SIZE \ | ||
506 | ((1024 - sizeof (void *)) / sizeof (bin_tree_t)) | ||
507 | |||
508 | struct bin_tree_storage_t | ||
509 | { | ||
510 | struct bin_tree_storage_t *next; | ||
511 | bin_tree_t data[BIN_TREE_STORAGE_SIZE]; | ||
512 | }; | ||
513 | typedef struct bin_tree_storage_t bin_tree_storage_t; | ||
514 | |||
515 | #define CONTEXT_WORD 1 | ||
516 | #define CONTEXT_NEWLINE (CONTEXT_WORD << 1) | ||
517 | #define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1) | ||
518 | #define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1) | ||
519 | |||
520 | #define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD) | ||
521 | #define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE) | ||
522 | #define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF) | ||
523 | #define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF) | ||
524 | #define IS_ORDINARY_CONTEXT(c) ((c) == 0) | ||
525 | |||
526 | #define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_') | ||
527 | #define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR) | ||
528 | #define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_') | ||
529 | #define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR) | ||
530 | |||
531 | #define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \ | ||
532 | ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ | ||
533 | || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ | ||
534 | || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\ | ||
535 | || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context))) | ||
536 | |||
537 | #define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \ | ||
538 | ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ | ||
539 | || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ | ||
540 | || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \ | ||
541 | || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context))) | ||
542 | |||
543 | struct re_dfastate_t | ||
544 | { | ||
545 | re_hashval_t hash; | ||
546 | re_node_set nodes; | ||
547 | re_node_set non_eps_nodes; | ||
548 | re_node_set inveclosure; | ||
549 | re_node_set *entrance_nodes; | ||
550 | struct re_dfastate_t **trtable, **word_trtable; | ||
551 | unsigned int context : 4; | ||
552 | unsigned int halt : 1; | ||
553 | /* If this state can accept `multi byte'. | ||
554 | Note that we refer to multibyte characters, and multi character | ||
555 | collating elements as `multi byte'. */ | ||
556 | unsigned int accept_mb : 1; | ||
557 | /* If this state has backreference node(s). */ | ||
558 | unsigned int has_backref : 1; | ||
559 | unsigned int has_constraint : 1; | ||
560 | }; | ||
561 | typedef struct re_dfastate_t re_dfastate_t; | ||
562 | |||
563 | struct re_state_table_entry | ||
564 | { | ||
565 | Idx num; | ||
566 | Idx alloc; | ||
567 | re_dfastate_t **array; | ||
568 | }; | ||
569 | |||
570 | /* Array type used in re_sub_match_last_t and re_sub_match_top_t. */ | ||
571 | |||
572 | typedef struct | ||
573 | { | ||
574 | Idx next_idx; | ||
575 | Idx alloc; | ||
576 | re_dfastate_t **array; | ||
577 | } state_array_t; | ||
578 | |||
579 | /* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */ | ||
580 | |||
581 | typedef struct | ||
582 | { | ||
583 | Idx node; | ||
584 | Idx str_idx; /* The position NODE match at. */ | ||
585 | state_array_t path; | ||
586 | } re_sub_match_last_t; | ||
587 | |||
588 | /* Store information about the node NODE whose type is OP_OPEN_SUBEXP. | ||
589 | And information about the node, whose type is OP_CLOSE_SUBEXP, | ||
590 | corresponding to NODE is stored in LASTS. */ | ||
591 | |||
592 | typedef struct | ||
593 | { | ||
594 | Idx str_idx; | ||
595 | Idx node; | ||
596 | state_array_t *path; | ||
597 | Idx alasts; /* Allocation size of LASTS. */ | ||
598 | Idx nlasts; /* The number of LASTS. */ | ||
599 | re_sub_match_last_t **lasts; | ||
600 | } re_sub_match_top_t; | ||
601 | |||
602 | struct re_backref_cache_entry | ||
603 | { | ||
604 | Idx node; | ||
605 | Idx str_idx; | ||
606 | Idx subexp_from; | ||
607 | Idx subexp_to; | ||
608 | char more; | ||
609 | char unused; | ||
610 | unsigned short int eps_reachable_subexps_map; | ||
611 | }; | ||
612 | |||
613 | typedef struct | ||
614 | { | ||
615 | /* The string object corresponding to the input string. */ | ||
616 | re_string_t input; | ||
617 | #if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) | ||
618 | const re_dfa_t *const dfa; | ||
619 | #else | ||
620 | const re_dfa_t *dfa; | ||
621 | #endif | ||
622 | /* EFLAGS of the argument of regexec. */ | ||
623 | int eflags; | ||
624 | /* Where the matching ends. */ | ||
625 | Idx match_last; | ||
626 | Idx last_node; | ||
627 | /* The state log used by the matcher. */ | ||
628 | re_dfastate_t **state_log; | ||
629 | Idx state_log_top; | ||
630 | /* Back reference cache. */ | ||
631 | Idx nbkref_ents; | ||
632 | Idx abkref_ents; | ||
633 | struct re_backref_cache_entry *bkref_ents; | ||
634 | int max_mb_elem_len; | ||
635 | Idx nsub_tops; | ||
636 | Idx asub_tops; | ||
637 | re_sub_match_top_t **sub_tops; | ||
638 | } re_match_context_t; | ||
639 | |||
640 | typedef struct | ||
641 | { | ||
642 | re_dfastate_t **sifted_states; | ||
643 | re_dfastate_t **limited_states; | ||
644 | Idx last_node; | ||
645 | Idx last_str_idx; | ||
646 | re_node_set limits; | ||
647 | } re_sift_context_t; | ||
648 | |||
649 | struct re_fail_stack_ent_t | ||
650 | { | ||
651 | Idx idx; | ||
652 | Idx node; | ||
653 | regmatch_t *regs; | ||
654 | re_node_set eps_via_nodes; | ||
655 | }; | ||
656 | |||
657 | struct re_fail_stack_t | ||
658 | { | ||
659 | Idx num; | ||
660 | Idx alloc; | ||
661 | struct re_fail_stack_ent_t *stack; | ||
662 | }; | ||
663 | |||
664 | struct re_dfa_t | ||
665 | { | ||
666 | re_token_t *nodes; | ||
667 | size_t nodes_alloc; | ||
668 | size_t nodes_len; | ||
669 | Idx *nexts; | ||
670 | Idx *org_indices; | ||
671 | re_node_set *edests; | ||
672 | re_node_set *eclosures; | ||
673 | re_node_set *inveclosures; | ||
674 | struct re_state_table_entry *state_table; | ||
675 | re_dfastate_t *init_state; | ||
676 | re_dfastate_t *init_state_word; | ||
677 | re_dfastate_t *init_state_nl; | ||
678 | re_dfastate_t *init_state_begbuf; | ||
679 | bin_tree_t *str_tree; | ||
680 | bin_tree_storage_t *str_tree_storage; | ||
681 | re_bitset_ptr_t sb_char; | ||
682 | int str_tree_storage_idx; | ||
683 | |||
684 | /* number of subexpressions `re_nsub' is in regex_t. */ | ||
685 | re_hashval_t state_hash_mask; | ||
686 | Idx init_node; | ||
687 | Idx nbackref; /* The number of backreference in this dfa. */ | ||
688 | |||
689 | /* Bitmap expressing which backreference is used. */ | ||
690 | bitset_word_t used_bkref_map; | ||
691 | bitset_word_t completed_bkref_map; | ||
692 | |||
693 | unsigned int has_plural_match : 1; | ||
694 | /* If this dfa has "multibyte node", which is a backreference or | ||
695 | a node which can accept multibyte character or multi character | ||
696 | collating element. */ | ||
697 | unsigned int has_mb_node : 1; | ||
698 | unsigned int is_utf8 : 1; | ||
699 | unsigned int map_notascii : 1; | ||
700 | unsigned int word_ops_used : 1; | ||
701 | int mb_cur_max; | ||
702 | bitset_t word_char; | ||
703 | reg_syntax_t syntax; | ||
704 | Idx *subexp_map; | ||
705 | #ifdef DEBUG | ||
706 | char* re_str; | ||
707 | #endif | ||
708 | #ifdef _LIBC | ||
709 | __libc_lock_define (, lock) | ||
710 | #endif | ||
711 | }; | ||
712 | |||
713 | #define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) | ||
714 | #define re_node_set_remove(set,id) \ | ||
715 | (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1)) | ||
716 | #define re_node_set_empty(p) ((p)->nelem = 0) | ||
717 | #define re_node_set_free(set) re_free ((set)->elems) | ||
718 | |||
719 | |||
720 | typedef enum | ||
721 | { | ||
722 | SB_CHAR, | ||
723 | MB_CHAR, | ||
724 | EQUIV_CLASS, | ||
725 | COLL_SYM, | ||
726 | CHAR_CLASS | ||
727 | } bracket_elem_type; | ||
728 | |||
729 | typedef struct | ||
730 | { | ||
731 | bracket_elem_type type; | ||
732 | union | ||
733 | { | ||
734 | unsigned char ch; | ||
735 | unsigned char *name; | ||
736 | wchar_t wch; | ||
737 | } opr; | ||
738 | } bracket_elem_t; | ||
739 | |||
740 | |||
741 | /* Inline functions for bitset_t operation. */ | ||
742 | |||
743 | static inline void | ||
744 | bitset_set (bitset_t set, Idx i) | ||
745 | { | ||
746 | set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS; | ||
747 | } | ||
748 | |||
749 | static inline void | ||
750 | bitset_clear (bitset_t set, Idx i) | ||
751 | { | ||
752 | set[i / BITSET_WORD_BITS] &= ~ ((bitset_word_t) 1 << i % BITSET_WORD_BITS); | ||
753 | } | ||
754 | |||
755 | static inline bool | ||
756 | bitset_contain (const bitset_t set, Idx i) | ||
757 | { | ||
758 | return (set[i / BITSET_WORD_BITS] >> i % BITSET_WORD_BITS) & 1; | ||
759 | } | ||
760 | |||
761 | static inline void | ||
762 | bitset_empty (bitset_t set) | ||
763 | { | ||
764 | memset (set, '\0', sizeof (bitset_t)); | ||
765 | } | ||
766 | |||
767 | static inline void | ||
768 | bitset_set_all (bitset_t set) | ||
769 | { | ||
770 | memset (set, -1, sizeof (bitset_word_t) * (SBC_MAX / BITSET_WORD_BITS)); | ||
771 | if (SBC_MAX % BITSET_WORD_BITS != 0) | ||
772 | set[BITSET_WORDS - 1] = | ||
773 | ((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1; | ||
774 | } | ||
775 | |||
776 | static inline void | ||
777 | bitset_copy (bitset_t dest, const bitset_t src) | ||
778 | { | ||
779 | memcpy (dest, src, sizeof (bitset_t)); | ||
780 | } | ||
781 | |||
782 | static inline void | ||
783 | bitset_not (bitset_t set) | ||
784 | { | ||
785 | int bitset_i; | ||
786 | for (bitset_i = 0; bitset_i < SBC_MAX / BITSET_WORD_BITS; ++bitset_i) | ||
787 | set[bitset_i] = ~set[bitset_i]; | ||
788 | if (SBC_MAX % BITSET_WORD_BITS != 0) | ||
789 | set[BITSET_WORDS - 1] = | ||
790 | ((((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1) | ||
791 | & ~set[BITSET_WORDS - 1]); | ||
792 | } | ||
793 | |||
794 | static inline void | ||
795 | bitset_merge (bitset_t dest, const bitset_t src) | ||
796 | { | ||
797 | int bitset_i; | ||
798 | for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) | ||
799 | dest[bitset_i] |= src[bitset_i]; | ||
800 | } | ||
801 | |||
802 | static inline void | ||
803 | bitset_mask (bitset_t dest, const bitset_t src) | ||
804 | { | ||
805 | int bitset_i; | ||
806 | for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) | ||
807 | dest[bitset_i] &= src[bitset_i]; | ||
808 | } | ||
809 | |||
810 | #ifdef RE_ENABLE_I18N | ||
811 | /* Inline functions for re_string. */ | ||
812 | static inline int | ||
813 | internal_function __attribute ((pure)) | ||
814 | re_string_char_size_at (const re_string_t *pstr, Idx idx) | ||
815 | { | ||
816 | int byte_idx; | ||
817 | if (pstr->mb_cur_max == 1) | ||
818 | return 1; | ||
819 | for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx) | ||
820 | if (pstr->wcs[idx + byte_idx] != WEOF) | ||
821 | break; | ||
822 | return byte_idx; | ||
823 | } | ||
824 | |||
825 | static inline wint_t | ||
826 | internal_function __attribute ((pure)) | ||
827 | re_string_wchar_at (const re_string_t *pstr, Idx idx) | ||
828 | { | ||
829 | if (pstr->mb_cur_max == 1) | ||
830 | return (wint_t) pstr->mbs[idx]; | ||
831 | return (wint_t) pstr->wcs[idx]; | ||
832 | } | ||
833 | |||
834 | static int | ||
835 | internal_function __attribute ((pure)) | ||
836 | re_string_elem_size_at (const re_string_t *pstr, Idx idx) | ||
837 | { | ||
838 | # ifdef _LIBC | ||
839 | const unsigned char *p, *extra; | ||
840 | const int32_t *table, *indirect; | ||
841 | int32_t tmp; | ||
842 | # include <locale/weight.h> | ||
843 | uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); | ||
844 | |||
845 | if (nrules != 0) | ||
846 | { | ||
847 | table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); | ||
848 | extra = (const unsigned char *) | ||
849 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); | ||
850 | indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, | ||
851 | _NL_COLLATE_INDIRECTMB); | ||
852 | p = pstr->mbs + idx; | ||
853 | tmp = findidx (&p); | ||
854 | return p - pstr->mbs - idx; | ||
855 | } | ||
856 | else | ||
857 | # endif /* _LIBC */ | ||
858 | return 1; | ||
859 | } | ||
860 | #endif /* RE_ENABLE_I18N */ | ||
861 | |||
862 | #endif /* _REGEX_INTERNAL_H */ | ||
diff --git a/gl/regexec.c b/gl/regexec.c new file mode 100644 index 00000000..7c186aa2 --- /dev/null +++ b/gl/regexec.c | |||
@@ -0,0 +1,4398 @@ | |||
1 | /* Extended regular expression matching and search library. | ||
2 | Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. | ||
3 | This file is part of the GNU C Library. | ||
4 | Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License along | ||
17 | with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags, | ||
21 | Idx n) internal_function; | ||
22 | static void match_ctx_clean (re_match_context_t *mctx) internal_function; | ||
23 | static void match_ctx_free (re_match_context_t *cache) internal_function; | ||
24 | static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, Idx node, | ||
25 | Idx str_idx, Idx from, Idx to) | ||
26 | internal_function; | ||
27 | static Idx search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx) | ||
28 | internal_function; | ||
29 | static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, Idx node, | ||
30 | Idx str_idx) internal_function; | ||
31 | static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop, | ||
32 | Idx node, Idx str_idx) | ||
33 | internal_function; | ||
34 | static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, | ||
35 | re_dfastate_t **limited_sts, Idx last_node, | ||
36 | Idx last_str_idx) | ||
37 | internal_function; | ||
38 | static reg_errcode_t re_search_internal (const regex_t *preg, | ||
39 | const char *string, Idx length, | ||
40 | Idx start, Idx last_start, Idx stop, | ||
41 | size_t nmatch, regmatch_t pmatch[], | ||
42 | int eflags) internal_function; | ||
43 | static regoff_t re_search_2_stub (struct re_pattern_buffer *bufp, | ||
44 | const char *string1, Idx length1, | ||
45 | const char *string2, Idx length2, | ||
46 | Idx start, regoff_t range, | ||
47 | struct re_registers *regs, | ||
48 | Idx stop, bool ret_len) internal_function; | ||
49 | static regoff_t re_search_stub (struct re_pattern_buffer *bufp, | ||
50 | const char *string, Idx length, Idx start, | ||
51 | regoff_t range, Idx stop, | ||
52 | struct re_registers *regs, | ||
53 | bool ret_len) internal_function; | ||
54 | static unsigned int re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, | ||
55 | Idx nregs, int regs_allocated) | ||
56 | internal_function; | ||
57 | static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx) | ||
58 | internal_function; | ||
59 | static Idx check_matching (re_match_context_t *mctx, bool fl_longest_match, | ||
60 | Idx *p_match_first) internal_function; | ||
61 | static Idx check_halt_state_context (const re_match_context_t *mctx, | ||
62 | const re_dfastate_t *state, Idx idx) | ||
63 | internal_function; | ||
64 | static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, | ||
65 | regmatch_t *prev_idx_match, Idx cur_node, | ||
66 | Idx cur_idx, Idx nmatch) internal_function; | ||
67 | static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs, | ||
68 | Idx str_idx, Idx dest_node, Idx nregs, | ||
69 | regmatch_t *regs, | ||
70 | re_node_set *eps_via_nodes) | ||
71 | internal_function; | ||
72 | static reg_errcode_t set_regs (const regex_t *preg, | ||
73 | const re_match_context_t *mctx, | ||
74 | size_t nmatch, regmatch_t *pmatch, | ||
75 | bool fl_backtrack) internal_function; | ||
76 | static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs) | ||
77 | internal_function; | ||
78 | |||
79 | #ifdef RE_ENABLE_I18N | ||
80 | static int sift_states_iter_mb (const re_match_context_t *mctx, | ||
81 | re_sift_context_t *sctx, | ||
82 | Idx node_idx, Idx str_idx, Idx max_str_idx) | ||
83 | internal_function; | ||
84 | #endif /* RE_ENABLE_I18N */ | ||
85 | static reg_errcode_t sift_states_backward (const re_match_context_t *mctx, | ||
86 | re_sift_context_t *sctx) | ||
87 | internal_function; | ||
88 | static reg_errcode_t build_sifted_states (const re_match_context_t *mctx, | ||
89 | re_sift_context_t *sctx, Idx str_idx, | ||
90 | re_node_set *cur_dest) | ||
91 | internal_function; | ||
92 | static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx, | ||
93 | re_sift_context_t *sctx, | ||
94 | Idx str_idx, | ||
95 | re_node_set *dest_nodes) | ||
96 | internal_function; | ||
97 | static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa, | ||
98 | re_node_set *dest_nodes, | ||
99 | const re_node_set *candidates) | ||
100 | internal_function; | ||
101 | static bool check_dst_limits (const re_match_context_t *mctx, | ||
102 | const re_node_set *limits, | ||
103 | Idx dst_node, Idx dst_idx, Idx src_node, | ||
104 | Idx src_idx) internal_function; | ||
105 | static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, | ||
106 | int boundaries, Idx subexp_idx, | ||
107 | Idx from_node, Idx bkref_idx) | ||
108 | internal_function; | ||
109 | static int check_dst_limits_calc_pos (const re_match_context_t *mctx, | ||
110 | Idx limit, Idx subexp_idx, | ||
111 | Idx node, Idx str_idx, | ||
112 | Idx bkref_idx) internal_function; | ||
113 | static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa, | ||
114 | re_node_set *dest_nodes, | ||
115 | const re_node_set *candidates, | ||
116 | re_node_set *limits, | ||
117 | struct re_backref_cache_entry *bkref_ents, | ||
118 | Idx str_idx) internal_function; | ||
119 | static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx, | ||
120 | re_sift_context_t *sctx, | ||
121 | Idx str_idx, const re_node_set *candidates) | ||
122 | internal_function; | ||
123 | static reg_errcode_t merge_state_array (const re_dfa_t *dfa, | ||
124 | re_dfastate_t **dst, | ||
125 | re_dfastate_t **src, Idx num) | ||
126 | internal_function; | ||
127 | static re_dfastate_t *find_recover_state (reg_errcode_t *err, | ||
128 | re_match_context_t *mctx) internal_function; | ||
129 | static re_dfastate_t *transit_state (reg_errcode_t *err, | ||
130 | re_match_context_t *mctx, | ||
131 | re_dfastate_t *state) internal_function; | ||
132 | static re_dfastate_t *merge_state_with_log (reg_errcode_t *err, | ||
133 | re_match_context_t *mctx, | ||
134 | re_dfastate_t *next_state) | ||
135 | internal_function; | ||
136 | static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx, | ||
137 | re_node_set *cur_nodes, | ||
138 | Idx str_idx) internal_function; | ||
139 | #if 0 | ||
140 | static re_dfastate_t *transit_state_sb (reg_errcode_t *err, | ||
141 | re_match_context_t *mctx, | ||
142 | re_dfastate_t *pstate) | ||
143 | internal_function; | ||
144 | #endif | ||
145 | #ifdef RE_ENABLE_I18N | ||
146 | static reg_errcode_t transit_state_mb (re_match_context_t *mctx, | ||
147 | re_dfastate_t *pstate) | ||
148 | internal_function; | ||
149 | #endif /* RE_ENABLE_I18N */ | ||
150 | static reg_errcode_t transit_state_bkref (re_match_context_t *mctx, | ||
151 | const re_node_set *nodes) | ||
152 | internal_function; | ||
153 | static reg_errcode_t get_subexp (re_match_context_t *mctx, | ||
154 | Idx bkref_node, Idx bkref_str_idx) | ||
155 | internal_function; | ||
156 | static reg_errcode_t get_subexp_sub (re_match_context_t *mctx, | ||
157 | const re_sub_match_top_t *sub_top, | ||
158 | re_sub_match_last_t *sub_last, | ||
159 | Idx bkref_node, Idx bkref_str) | ||
160 | internal_function; | ||
161 | static Idx find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, | ||
162 | Idx subexp_idx, int type) internal_function; | ||
163 | static reg_errcode_t check_arrival (re_match_context_t *mctx, | ||
164 | state_array_t *path, Idx top_node, | ||
165 | Idx top_str, Idx last_node, Idx last_str, | ||
166 | int type) internal_function; | ||
167 | static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx, | ||
168 | Idx str_idx, | ||
169 | re_node_set *cur_nodes, | ||
170 | re_node_set *next_nodes) | ||
171 | internal_function; | ||
172 | static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa, | ||
173 | re_node_set *cur_nodes, | ||
174 | Idx ex_subexp, int type) | ||
175 | internal_function; | ||
176 | static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa, | ||
177 | re_node_set *dst_nodes, | ||
178 | Idx target, Idx ex_subexp, | ||
179 | int type) internal_function; | ||
180 | static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx, | ||
181 | re_node_set *cur_nodes, Idx cur_str, | ||
182 | Idx subexp_num, int type) | ||
183 | internal_function; | ||
184 | static bool build_trtable (const re_dfa_t *dfa, | ||
185 | re_dfastate_t *state) internal_function; | ||
186 | #ifdef RE_ENABLE_I18N | ||
187 | static int check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx, | ||
188 | const re_string_t *input, Idx idx) | ||
189 | internal_function; | ||
190 | # ifdef _LIBC | ||
191 | static unsigned int find_collation_sequence_value (const unsigned char *mbs, | ||
192 | size_t name_len) | ||
193 | internal_function; | ||
194 | # endif /* _LIBC */ | ||
195 | #endif /* RE_ENABLE_I18N */ | ||
196 | static Idx group_nodes_into_DFAstates (const re_dfa_t *dfa, | ||
197 | const re_dfastate_t *state, | ||
198 | re_node_set *states_node, | ||
199 | bitset_t *states_ch) internal_function; | ||
200 | static bool check_node_accept (const re_match_context_t *mctx, | ||
201 | const re_token_t *node, Idx idx) | ||
202 | internal_function; | ||
203 | static reg_errcode_t extend_buffers (re_match_context_t *mctx) | ||
204 | internal_function; | ||
205 | |||
206 | /* Entry point for POSIX code. */ | ||
207 | |||
208 | /* regexec searches for a given pattern, specified by PREG, in the | ||
209 | string STRING. | ||
210 | |||
211 | If NMATCH is zero or REG_NOSUB was set in the cflags argument to | ||
212 | `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at | ||
213 | least NMATCH elements, and we set them to the offsets of the | ||
214 | corresponding matched substrings. | ||
215 | |||
216 | EFLAGS specifies `execution flags' which affect matching: if | ||
217 | REG_NOTBOL is set, then ^ does not match at the beginning of the | ||
218 | string; if REG_NOTEOL is set, then $ does not match at the end. | ||
219 | |||
220 | We return 0 if we find a match and REG_NOMATCH if not. */ | ||
221 | |||
222 | int | ||
223 | regexec (preg, string, nmatch, pmatch, eflags) | ||
224 | const regex_t *__restrict preg; | ||
225 | const char *__restrict string; | ||
226 | size_t nmatch; | ||
227 | regmatch_t pmatch[]; | ||
228 | int eflags; | ||
229 | { | ||
230 | reg_errcode_t err; | ||
231 | Idx start, length; | ||
232 | #ifdef _LIBC | ||
233 | re_dfa_t *dfa = (re_dfa_t *) preg->buffer; | ||
234 | #endif | ||
235 | |||
236 | if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND)) | ||
237 | return REG_BADPAT; | ||
238 | |||
239 | if (eflags & REG_STARTEND) | ||
240 | { | ||
241 | start = pmatch[0].rm_so; | ||
242 | length = pmatch[0].rm_eo; | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | start = 0; | ||
247 | length = strlen (string); | ||
248 | } | ||
249 | |||
250 | __libc_lock_lock (dfa->lock); | ||
251 | if (preg->no_sub) | ||
252 | err = re_search_internal (preg, string, length, start, length, | ||
253 | length, 0, NULL, eflags); | ||
254 | else | ||
255 | err = re_search_internal (preg, string, length, start, length, | ||
256 | length, nmatch, pmatch, eflags); | ||
257 | __libc_lock_unlock (dfa->lock); | ||
258 | return err != REG_NOERROR; | ||
259 | } | ||
260 | |||
261 | #ifdef _LIBC | ||
262 | # include <shlib-compat.h> | ||
263 | versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4); | ||
264 | |||
265 | # if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4) | ||
266 | __typeof__ (__regexec) __compat_regexec; | ||
267 | |||
268 | int | ||
269 | attribute_compat_text_section | ||
270 | __compat_regexec (const regex_t *__restrict preg, | ||
271 | const char *__restrict string, size_t nmatch, | ||
272 | regmatch_t pmatch[], int eflags) | ||
273 | { | ||
274 | return regexec (preg, string, nmatch, pmatch, | ||
275 | eflags & (REG_NOTBOL | REG_NOTEOL)); | ||
276 | } | ||
277 | compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0); | ||
278 | # endif | ||
279 | #endif | ||
280 | |||
281 | /* Entry points for GNU code. */ | ||
282 | |||
283 | /* re_match, re_search, re_match_2, re_search_2 | ||
284 | |||
285 | The former two functions operate on STRING with length LENGTH, | ||
286 | while the later two operate on concatenation of STRING1 and STRING2 | ||
287 | with lengths LENGTH1 and LENGTH2, respectively. | ||
288 | |||
289 | re_match() matches the compiled pattern in BUFP against the string, | ||
290 | starting at index START. | ||
291 | |||
292 | re_search() first tries matching at index START, then it tries to match | ||
293 | starting from index START + 1, and so on. The last start position tried | ||
294 | is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same | ||
295 | way as re_match().) | ||
296 | |||
297 | The parameter STOP of re_{match,search}_2 specifies that no match exceeding | ||
298 | the first STOP characters of the concatenation of the strings should be | ||
299 | concerned. | ||
300 | |||
301 | If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match | ||
302 | and all groups is stored in REGS. (For the "_2" variants, the offsets are | ||
303 | computed relative to the concatenation, not relative to the individual | ||
304 | strings.) | ||
305 | |||
306 | On success, re_match* functions return the length of the match, re_search* | ||
307 | return the position of the start of the match. Return value -1 means no | ||
308 | match was found and -2 indicates an internal error. */ | ||
309 | |||
310 | regoff_t | ||
311 | re_match (bufp, string, length, start, regs) | ||
312 | struct re_pattern_buffer *bufp; | ||
313 | const char *string; | ||
314 | Idx length, start; | ||
315 | struct re_registers *regs; | ||
316 | { | ||
317 | return re_search_stub (bufp, string, length, start, 0, length, regs, true); | ||
318 | } | ||
319 | #ifdef _LIBC | ||
320 | weak_alias (__re_match, re_match) | ||
321 | #endif | ||
322 | |||
323 | regoff_t | ||
324 | re_search (bufp, string, length, start, range, regs) | ||
325 | struct re_pattern_buffer *bufp; | ||
326 | const char *string; | ||
327 | Idx length, start; | ||
328 | regoff_t range; | ||
329 | struct re_registers *regs; | ||
330 | { | ||
331 | return re_search_stub (bufp, string, length, start, range, length, regs, | ||
332 | false); | ||
333 | } | ||
334 | #ifdef _LIBC | ||
335 | weak_alias (__re_search, re_search) | ||
336 | #endif | ||
337 | |||
338 | regoff_t | ||
339 | re_match_2 (bufp, string1, length1, string2, length2, start, regs, stop) | ||
340 | struct re_pattern_buffer *bufp; | ||
341 | const char *string1, *string2; | ||
342 | Idx length1, length2, start, stop; | ||
343 | struct re_registers *regs; | ||
344 | { | ||
345 | return re_search_2_stub (bufp, string1, length1, string2, length2, | ||
346 | start, 0, regs, stop, true); | ||
347 | } | ||
348 | #ifdef _LIBC | ||
349 | weak_alias (__re_match_2, re_match_2) | ||
350 | #endif | ||
351 | |||
352 | regoff_t | ||
353 | re_search_2 (bufp, string1, length1, string2, length2, start, range, regs, stop) | ||
354 | struct re_pattern_buffer *bufp; | ||
355 | const char *string1, *string2; | ||
356 | Idx length1, length2, start, stop; | ||
357 | regoff_t range; | ||
358 | struct re_registers *regs; | ||
359 | { | ||
360 | return re_search_2_stub (bufp, string1, length1, string2, length2, | ||
361 | start, range, regs, stop, false); | ||
362 | } | ||
363 | #ifdef _LIBC | ||
364 | weak_alias (__re_search_2, re_search_2) | ||
365 | #endif | ||
366 | |||
367 | static regoff_t | ||
368 | internal_function | ||
369 | re_search_2_stub (struct re_pattern_buffer *bufp, | ||
370 | const char *string1, Idx length1, | ||
371 | const char *string2, Idx length2, | ||
372 | Idx start, regoff_t range, struct re_registers *regs, | ||
373 | Idx stop, bool ret_len) | ||
374 | { | ||
375 | const char *str; | ||
376 | regoff_t rval; | ||
377 | Idx len = length1 + length2; | ||
378 | char *s = NULL; | ||
379 | |||
380 | if (BE (length1 < 0 || length2 < 0 || stop < 0 || len < length1, 0)) | ||
381 | return -2; | ||
382 | |||
383 | /* Concatenate the strings. */ | ||
384 | if (length2 > 0) | ||
385 | if (length1 > 0) | ||
386 | { | ||
387 | s = re_malloc (char, len); | ||
388 | |||
389 | if (BE (s == NULL, 0)) | ||
390 | return -2; | ||
391 | #ifdef _LIBC | ||
392 | memcpy (__mempcpy (s, string1, length1), string2, length2); | ||
393 | #else | ||
394 | memcpy (s, string1, length1); | ||
395 | memcpy (s + length1, string2, length2); | ||
396 | #endif | ||
397 | str = s; | ||
398 | } | ||
399 | else | ||
400 | str = string2; | ||
401 | else | ||
402 | str = string1; | ||
403 | |||
404 | rval = re_search_stub (bufp, str, len, start, range, stop, regs, | ||
405 | ret_len); | ||
406 | re_free (s); | ||
407 | return rval; | ||
408 | } | ||
409 | |||
410 | /* The parameters have the same meaning as those of re_search. | ||
411 | Additional parameters: | ||
412 | If RET_LEN is true the length of the match is returned (re_match style); | ||
413 | otherwise the position of the match is returned. */ | ||
414 | |||
415 | static regoff_t | ||
416 | internal_function | ||
417 | re_search_stub (struct re_pattern_buffer *bufp, | ||
418 | const char *string, Idx length, | ||
419 | Idx start, regoff_t range, Idx stop, struct re_registers *regs, | ||
420 | bool ret_len) | ||
421 | { | ||
422 | reg_errcode_t result; | ||
423 | regmatch_t *pmatch; | ||
424 | Idx nregs; | ||
425 | regoff_t rval; | ||
426 | int eflags = 0; | ||
427 | #ifdef _LIBC | ||
428 | re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; | ||
429 | #endif | ||
430 | Idx last_start = start + range; | ||
431 | |||
432 | /* Check for out-of-range. */ | ||
433 | if (BE (start < 0 || start > length, 0)) | ||
434 | return -1; | ||
435 | if (BE (length < last_start || (0 <= range && last_start < start), 0)) | ||
436 | last_start = length; | ||
437 | else if (BE (last_start < 0 || (range < 0 && start <= last_start), 0)) | ||
438 | last_start = 0; | ||
439 | |||
440 | __libc_lock_lock (dfa->lock); | ||
441 | |||
442 | eflags |= (bufp->not_bol) ? REG_NOTBOL : 0; | ||
443 | eflags |= (bufp->not_eol) ? REG_NOTEOL : 0; | ||
444 | |||
445 | /* Compile fastmap if we haven't yet. */ | ||
446 | if (start < last_start && bufp->fastmap != NULL && !bufp->fastmap_accurate) | ||
447 | re_compile_fastmap (bufp); | ||
448 | |||
449 | if (BE (bufp->no_sub, 0)) | ||
450 | regs = NULL; | ||
451 | |||
452 | /* We need at least 1 register. */ | ||
453 | if (regs == NULL) | ||
454 | nregs = 1; | ||
455 | else if (BE (bufp->regs_allocated == REGS_FIXED | ||
456 | && regs->num_regs <= bufp->re_nsub, 0)) | ||
457 | { | ||
458 | nregs = regs->num_regs; | ||
459 | if (BE (nregs < 1, 0)) | ||
460 | { | ||
461 | /* Nothing can be copied to regs. */ | ||
462 | regs = NULL; | ||
463 | nregs = 1; | ||
464 | } | ||
465 | } | ||
466 | else | ||
467 | nregs = bufp->re_nsub + 1; | ||
468 | pmatch = re_malloc (regmatch_t, nregs); | ||
469 | if (BE (pmatch == NULL, 0)) | ||
470 | { | ||
471 | rval = -2; | ||
472 | goto out; | ||
473 | } | ||
474 | |||
475 | result = re_search_internal (bufp, string, length, start, last_start, stop, | ||
476 | nregs, pmatch, eflags); | ||
477 | |||
478 | rval = 0; | ||
479 | |||
480 | /* I hope we needn't fill ther regs with -1's when no match was found. */ | ||
481 | if (result != REG_NOERROR) | ||
482 | rval = -1; | ||
483 | else if (regs != NULL) | ||
484 | { | ||
485 | /* If caller wants register contents data back, copy them. */ | ||
486 | bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs, | ||
487 | bufp->regs_allocated); | ||
488 | if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0)) | ||
489 | rval = -2; | ||
490 | } | ||
491 | |||
492 | if (BE (rval == 0, 1)) | ||
493 | { | ||
494 | if (ret_len) | ||
495 | { | ||
496 | assert (pmatch[0].rm_so == start); | ||
497 | rval = pmatch[0].rm_eo - start; | ||
498 | } | ||
499 | else | ||
500 | rval = pmatch[0].rm_so; | ||
501 | } | ||
502 | re_free (pmatch); | ||
503 | out: | ||
504 | __libc_lock_unlock (dfa->lock); | ||
505 | return rval; | ||
506 | } | ||
507 | |||
508 | static unsigned int | ||
509 | internal_function | ||
510 | re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, Idx nregs, | ||
511 | int regs_allocated) | ||
512 | { | ||
513 | int rval = REGS_REALLOCATE; | ||
514 | Idx i; | ||
515 | Idx need_regs = nregs + 1; | ||
516 | /* We need one extra element beyond `num_regs' for the `-1' marker GNU code | ||
517 | uses. */ | ||
518 | |||
519 | /* Have the register data arrays been allocated? */ | ||
520 | if (regs_allocated == REGS_UNALLOCATED) | ||
521 | { /* No. So allocate them with malloc. */ | ||
522 | regs->start = re_malloc (regoff_t, need_regs); | ||
523 | if (BE (regs->start == NULL, 0)) | ||
524 | return REGS_UNALLOCATED; | ||
525 | regs->end = re_malloc (regoff_t, need_regs); | ||
526 | if (BE (regs->end == NULL, 0)) | ||
527 | { | ||
528 | re_free (regs->start); | ||
529 | return REGS_UNALLOCATED; | ||
530 | } | ||
531 | regs->num_regs = need_regs; | ||
532 | } | ||
533 | else if (regs_allocated == REGS_REALLOCATE) | ||
534 | { /* Yes. If we need more elements than were already | ||
535 | allocated, reallocate them. If we need fewer, just | ||
536 | leave it alone. */ | ||
537 | if (BE (need_regs > regs->num_regs, 0)) | ||
538 | { | ||
539 | regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs); | ||
540 | regoff_t *new_end; | ||
541 | if (BE (new_start == NULL, 0)) | ||
542 | return REGS_UNALLOCATED; | ||
543 | new_end = re_realloc (regs->end, regoff_t, need_regs); | ||
544 | if (BE (new_end == NULL, 0)) | ||
545 | { | ||
546 | re_free (new_start); | ||
547 | return REGS_UNALLOCATED; | ||
548 | } | ||
549 | regs->start = new_start; | ||
550 | regs->end = new_end; | ||
551 | regs->num_regs = need_regs; | ||
552 | } | ||
553 | } | ||
554 | else | ||
555 | { | ||
556 | assert (regs_allocated == REGS_FIXED); | ||
557 | /* This function may not be called with REGS_FIXED and nregs too big. */ | ||
558 | assert (regs->num_regs >= nregs); | ||
559 | rval = REGS_FIXED; | ||
560 | } | ||
561 | |||
562 | /* Copy the regs. */ | ||
563 | for (i = 0; i < nregs; ++i) | ||
564 | { | ||
565 | regs->start[i] = pmatch[i].rm_so; | ||
566 | regs->end[i] = pmatch[i].rm_eo; | ||
567 | } | ||
568 | for ( ; i < regs->num_regs; ++i) | ||
569 | regs->start[i] = regs->end[i] = -1; | ||
570 | |||
571 | return rval; | ||
572 | } | ||
573 | |||
574 | /* Set REGS to hold NUM_REGS registers, storing them in STARTS and | ||
575 | ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use | ||
576 | this memory for recording register information. STARTS and ENDS | ||
577 | must be allocated using the malloc library routine, and must each | ||
578 | be at least NUM_REGS * sizeof (regoff_t) bytes long. | ||
579 | |||
580 | If NUM_REGS == 0, then subsequent matches should allocate their own | ||
581 | register data. | ||
582 | |||
583 | Unless this function is called, the first search or match using | ||
584 | PATTERN_BUFFER will allocate its own register data, without | ||
585 | freeing the old data. */ | ||
586 | |||
587 | void | ||
588 | re_set_registers (bufp, regs, num_regs, starts, ends) | ||
589 | struct re_pattern_buffer *bufp; | ||
590 | struct re_registers *regs; | ||
591 | __re_size_t num_regs; | ||
592 | regoff_t *starts, *ends; | ||
593 | { | ||
594 | if (num_regs) | ||
595 | { | ||
596 | bufp->regs_allocated = REGS_REALLOCATE; | ||
597 | regs->num_regs = num_regs; | ||
598 | regs->start = starts; | ||
599 | regs->end = ends; | ||
600 | } | ||
601 | else | ||
602 | { | ||
603 | bufp->regs_allocated = REGS_UNALLOCATED; | ||
604 | regs->num_regs = 0; | ||
605 | regs->start = regs->end = NULL; | ||
606 | } | ||
607 | } | ||
608 | #ifdef _LIBC | ||
609 | weak_alias (__re_set_registers, re_set_registers) | ||
610 | #endif | ||
611 | |||
612 | /* Entry points compatible with 4.2 BSD regex library. We don't define | ||
613 | them unless specifically requested. */ | ||
614 | |||
615 | #if defined _REGEX_RE_COMP || defined _LIBC | ||
616 | int | ||
617 | # ifdef _LIBC | ||
618 | weak_function | ||
619 | # endif | ||
620 | re_exec (s) | ||
621 | const char *s; | ||
622 | { | ||
623 | return 0 == regexec (&re_comp_buf, s, 0, NULL, 0); | ||
624 | } | ||
625 | #endif /* _REGEX_RE_COMP */ | ||
626 | |||
627 | /* Internal entry point. */ | ||
628 | |||
629 | /* Searches for a compiled pattern PREG in the string STRING, whose | ||
630 | length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same | ||
631 | meaning as with regexec. LAST_START is START + RANGE, where | ||
632 | START and RANGE have the same meaning as with re_search. | ||
633 | Return REG_NOERROR if we find a match, and REG_NOMATCH if not, | ||
634 | otherwise return the error code. | ||
635 | Note: We assume front end functions already check ranges. | ||
636 | (0 <= LAST_START && LAST_START <= LENGTH) */ | ||
637 | |||
638 | static reg_errcode_t | ||
639 | internal_function | ||
640 | re_search_internal (const regex_t *preg, | ||
641 | const char *string, Idx length, | ||
642 | Idx start, Idx last_start, Idx stop, | ||
643 | size_t nmatch, regmatch_t pmatch[], | ||
644 | int eflags) | ||
645 | { | ||
646 | reg_errcode_t err; | ||
647 | const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; | ||
648 | Idx left_lim, right_lim; | ||
649 | int incr; | ||
650 | bool fl_longest_match; | ||
651 | int match_kind; | ||
652 | Idx match_first; | ||
653 | Idx match_last = REG_MISSING; | ||
654 | Idx extra_nmatch; | ||
655 | bool sb; | ||
656 | int ch; | ||
657 | #if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) | ||
658 | re_match_context_t mctx = { .dfa = dfa }; | ||
659 | #else | ||
660 | re_match_context_t mctx; | ||
661 | #endif | ||
662 | char *fastmap = ((preg->fastmap != NULL && preg->fastmap_accurate | ||
663 | && start != last_start && !preg->can_be_null) | ||
664 | ? preg->fastmap : NULL); | ||
665 | RE_TRANSLATE_TYPE t = preg->translate; | ||
666 | |||
667 | #if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) | ||
668 | memset (&mctx, '\0', sizeof (re_match_context_t)); | ||
669 | mctx.dfa = dfa; | ||
670 | #endif | ||
671 | |||
672 | extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0; | ||
673 | nmatch -= extra_nmatch; | ||
674 | |||
675 | /* Check if the DFA haven't been compiled. */ | ||
676 | if (BE (preg->used == 0 || dfa->init_state == NULL | ||
677 | || dfa->init_state_word == NULL || dfa->init_state_nl == NULL | ||
678 | || dfa->init_state_begbuf == NULL, 0)) | ||
679 | return REG_NOMATCH; | ||
680 | |||
681 | #ifdef DEBUG | ||
682 | /* We assume front-end functions already check them. */ | ||
683 | assert (0 <= last_start && last_start <= length); | ||
684 | #endif | ||
685 | |||
686 | /* If initial states with non-begbuf contexts have no elements, | ||
687 | the regex must be anchored. If preg->newline_anchor is set, | ||
688 | we'll never use init_state_nl, so do not check it. */ | ||
689 | if (dfa->init_state->nodes.nelem == 0 | ||
690 | && dfa->init_state_word->nodes.nelem == 0 | ||
691 | && (dfa->init_state_nl->nodes.nelem == 0 | ||
692 | || !preg->newline_anchor)) | ||
693 | { | ||
694 | if (start != 0 && last_start != 0) | ||
695 | return REG_NOMATCH; | ||
696 | start = last_start = 0; | ||
697 | } | ||
698 | |||
699 | /* We must check the longest matching, if nmatch > 0. */ | ||
700 | fl_longest_match = (nmatch != 0 || dfa->nbackref); | ||
701 | |||
702 | err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1, | ||
703 | preg->translate, preg->syntax & RE_ICASE, dfa); | ||
704 | if (BE (err != REG_NOERROR, 0)) | ||
705 | goto free_return; | ||
706 | mctx.input.stop = stop; | ||
707 | mctx.input.raw_stop = stop; | ||
708 | mctx.input.newline_anchor = preg->newline_anchor; | ||
709 | |||
710 | err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2); | ||
711 | if (BE (err != REG_NOERROR, 0)) | ||
712 | goto free_return; | ||
713 | |||
714 | /* We will log all the DFA states through which the dfa pass, | ||
715 | if nmatch > 1, or this dfa has "multibyte node", which is a | ||
716 | back-reference or a node which can accept multibyte character or | ||
717 | multi character collating element. */ | ||
718 | if (nmatch > 1 || dfa->has_mb_node) | ||
719 | { | ||
720 | /* Avoid overflow. */ | ||
721 | if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= mctx.input.bufs_len, 0)) | ||
722 | { | ||
723 | err = REG_ESPACE; | ||
724 | goto free_return; | ||
725 | } | ||
726 | |||
727 | mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1); | ||
728 | if (BE (mctx.state_log == NULL, 0)) | ||
729 | { | ||
730 | err = REG_ESPACE; | ||
731 | goto free_return; | ||
732 | } | ||
733 | } | ||
734 | else | ||
735 | mctx.state_log = NULL; | ||
736 | |||
737 | match_first = start; | ||
738 | mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF | ||
739 | : CONTEXT_NEWLINE | CONTEXT_BEGBUF; | ||
740 | |||
741 | /* Check incrementally whether of not the input string match. */ | ||
742 | incr = (last_start < start) ? -1 : 1; | ||
743 | left_lim = (last_start < start) ? last_start : start; | ||
744 | right_lim = (last_start < start) ? start : last_start; | ||
745 | sb = dfa->mb_cur_max == 1; | ||
746 | match_kind = | ||
747 | (fastmap | ||
748 | ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0) | ||
749 | | (start <= last_start ? 2 : 0) | ||
750 | | (t != NULL ? 1 : 0)) | ||
751 | : 8); | ||
752 | |||
753 | for (;; match_first += incr) | ||
754 | { | ||
755 | err = REG_NOMATCH; | ||
756 | if (match_first < left_lim || right_lim < match_first) | ||
757 | goto free_return; | ||
758 | |||
759 | /* Advance as rapidly as possible through the string, until we | ||
760 | find a plausible place to start matching. This may be done | ||
761 | with varying efficiency, so there are various possibilities: | ||
762 | only the most common of them are specialized, in order to | ||
763 | save on code size. We use a switch statement for speed. */ | ||
764 | switch (match_kind) | ||
765 | { | ||
766 | case 8: | ||
767 | /* No fastmap. */ | ||
768 | break; | ||
769 | |||
770 | case 7: | ||
771 | /* Fastmap with single-byte translation, match forward. */ | ||
772 | while (BE (match_first < right_lim, 1) | ||
773 | && !fastmap[t[(unsigned char) string[match_first]]]) | ||
774 | ++match_first; | ||
775 | goto forward_match_found_start_or_reached_end; | ||
776 | |||
777 | case 6: | ||
778 | /* Fastmap without translation, match forward. */ | ||
779 | while (BE (match_first < right_lim, 1) | ||
780 | && !fastmap[(unsigned char) string[match_first]]) | ||
781 | ++match_first; | ||
782 | |||
783 | forward_match_found_start_or_reached_end: | ||
784 | if (BE (match_first == right_lim, 0)) | ||
785 | { | ||
786 | ch = match_first >= length | ||
787 | ? 0 : (unsigned char) string[match_first]; | ||
788 | if (!fastmap[t ? t[ch] : ch]) | ||
789 | goto free_return; | ||
790 | } | ||
791 | break; | ||
792 | |||
793 | case 4: | ||
794 | case 5: | ||
795 | /* Fastmap without multi-byte translation, match backwards. */ | ||
796 | while (match_first >= left_lim) | ||
797 | { | ||
798 | ch = match_first >= length | ||
799 | ? 0 : (unsigned char) string[match_first]; | ||
800 | if (fastmap[t ? t[ch] : ch]) | ||
801 | break; | ||
802 | --match_first; | ||
803 | } | ||
804 | if (match_first < left_lim) | ||
805 | goto free_return; | ||
806 | break; | ||
807 | |||
808 | default: | ||
809 | /* In this case, we can't determine easily the current byte, | ||
810 | since it might be a component byte of a multibyte | ||
811 | character. Then we use the constructed buffer instead. */ | ||
812 | for (;;) | ||
813 | { | ||
814 | /* If MATCH_FIRST is out of the valid range, reconstruct the | ||
815 | buffers. */ | ||
816 | __re_size_t offset = match_first - mctx.input.raw_mbs_idx; | ||
817 | if (BE (offset >= (__re_size_t) mctx.input.valid_raw_len, 0)) | ||
818 | { | ||
819 | err = re_string_reconstruct (&mctx.input, match_first, | ||
820 | eflags); | ||
821 | if (BE (err != REG_NOERROR, 0)) | ||
822 | goto free_return; | ||
823 | |||
824 | offset = match_first - mctx.input.raw_mbs_idx; | ||
825 | } | ||
826 | /* If MATCH_FIRST is out of the buffer, leave it as '\0'. | ||
827 | Note that MATCH_FIRST must not be smaller than 0. */ | ||
828 | ch = (match_first >= length | ||
829 | ? 0 : re_string_byte_at (&mctx.input, offset)); | ||
830 | if (fastmap[ch]) | ||
831 | break; | ||
832 | match_first += incr; | ||
833 | if (match_first < left_lim || match_first > right_lim) | ||
834 | { | ||
835 | err = REG_NOMATCH; | ||
836 | goto free_return; | ||
837 | } | ||
838 | } | ||
839 | break; | ||
840 | } | ||
841 | |||
842 | /* Reconstruct the buffers so that the matcher can assume that | ||
843 | the matching starts from the beginning of the buffer. */ | ||
844 | err = re_string_reconstruct (&mctx.input, match_first, eflags); | ||
845 | if (BE (err != REG_NOERROR, 0)) | ||
846 | goto free_return; | ||
847 | |||
848 | #ifdef RE_ENABLE_I18N | ||
849 | /* Don't consider this char as a possible match start if it part, | ||
850 | yet isn't the head, of a multibyte character. */ | ||
851 | if (!sb && !re_string_first_byte (&mctx.input, 0)) | ||
852 | continue; | ||
853 | #endif | ||
854 | |||
855 | /* It seems to be appropriate one, then use the matcher. */ | ||
856 | /* We assume that the matching starts from 0. */ | ||
857 | mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0; | ||
858 | match_last = check_matching (&mctx, fl_longest_match, | ||
859 | start <= last_start ? &match_first : NULL); | ||
860 | if (match_last != REG_MISSING) | ||
861 | { | ||
862 | if (BE (match_last == REG_ERROR, 0)) | ||
863 | { | ||
864 | err = REG_ESPACE; | ||
865 | goto free_return; | ||
866 | } | ||
867 | else | ||
868 | { | ||
869 | mctx.match_last = match_last; | ||
870 | if ((!preg->no_sub && nmatch > 1) || dfa->nbackref) | ||
871 | { | ||
872 | re_dfastate_t *pstate = mctx.state_log[match_last]; | ||
873 | mctx.last_node = check_halt_state_context (&mctx, pstate, | ||
874 | match_last); | ||
875 | } | ||
876 | if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match) | ||
877 | || dfa->nbackref) | ||
878 | { | ||
879 | err = prune_impossible_nodes (&mctx); | ||
880 | if (err == REG_NOERROR) | ||
881 | break; | ||
882 | if (BE (err != REG_NOMATCH, 0)) | ||
883 | goto free_return; | ||
884 | match_last = REG_MISSING; | ||
885 | } | ||
886 | else | ||
887 | break; /* We found a match. */ | ||
888 | } | ||
889 | } | ||
890 | |||
891 | match_ctx_clean (&mctx); | ||
892 | } | ||
893 | |||
894 | #ifdef DEBUG | ||
895 | assert (match_last != REG_MISSING); | ||
896 | assert (err == REG_NOERROR); | ||
897 | #endif | ||
898 | |||
899 | /* Set pmatch[] if we need. */ | ||
900 | if (nmatch > 0) | ||
901 | { | ||
902 | Idx reg_idx; | ||
903 | |||
904 | /* Initialize registers. */ | ||
905 | for (reg_idx = 1; reg_idx < nmatch; ++reg_idx) | ||
906 | pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; | ||
907 | |||
908 | /* Set the points where matching start/end. */ | ||
909 | pmatch[0].rm_so = 0; | ||
910 | pmatch[0].rm_eo = mctx.match_last; | ||
911 | /* FIXME: This function should fail if mctx.match_last exceeds | ||
912 | the maximum possible regoff_t value. We need a new error | ||
913 | code REG_OVERFLOW. */ | ||
914 | |||
915 | if (!preg->no_sub && nmatch > 1) | ||
916 | { | ||
917 | err = set_regs (preg, &mctx, nmatch, pmatch, | ||
918 | dfa->has_plural_match && dfa->nbackref > 0); | ||
919 | if (BE (err != REG_NOERROR, 0)) | ||
920 | goto free_return; | ||
921 | } | ||
922 | |||
923 | /* At last, add the offset to the each registers, since we slided | ||
924 | the buffers so that we could assume that the matching starts | ||
925 | from 0. */ | ||
926 | for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) | ||
927 | if (pmatch[reg_idx].rm_so != -1) | ||
928 | { | ||
929 | #ifdef RE_ENABLE_I18N | ||
930 | if (BE (mctx.input.offsets_needed != 0, 0)) | ||
931 | { | ||
932 | pmatch[reg_idx].rm_so = | ||
933 | (pmatch[reg_idx].rm_so == mctx.input.valid_len | ||
934 | ? mctx.input.valid_raw_len | ||
935 | : mctx.input.offsets[pmatch[reg_idx].rm_so]); | ||
936 | pmatch[reg_idx].rm_eo = | ||
937 | (pmatch[reg_idx].rm_eo == mctx.input.valid_len | ||
938 | ? mctx.input.valid_raw_len | ||
939 | : mctx.input.offsets[pmatch[reg_idx].rm_eo]); | ||
940 | } | ||
941 | #else | ||
942 | assert (mctx.input.offsets_needed == 0); | ||
943 | #endif | ||
944 | pmatch[reg_idx].rm_so += match_first; | ||
945 | pmatch[reg_idx].rm_eo += match_first; | ||
946 | } | ||
947 | for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx) | ||
948 | { | ||
949 | pmatch[nmatch + reg_idx].rm_so = -1; | ||
950 | pmatch[nmatch + reg_idx].rm_eo = -1; | ||
951 | } | ||
952 | |||
953 | if (dfa->subexp_map) | ||
954 | for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++) | ||
955 | if (dfa->subexp_map[reg_idx] != reg_idx) | ||
956 | { | ||
957 | pmatch[reg_idx + 1].rm_so | ||
958 | = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so; | ||
959 | pmatch[reg_idx + 1].rm_eo | ||
960 | = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo; | ||
961 | } | ||
962 | } | ||
963 | |||
964 | free_return: | ||
965 | re_free (mctx.state_log); | ||
966 | if (dfa->nbackref) | ||
967 | match_ctx_free (&mctx); | ||
968 | re_string_destruct (&mctx.input); | ||
969 | return err; | ||
970 | } | ||
971 | |||
972 | static reg_errcode_t | ||
973 | internal_function | ||
974 | prune_impossible_nodes (re_match_context_t *mctx) | ||
975 | { | ||
976 | const re_dfa_t *const dfa = mctx->dfa; | ||
977 | Idx halt_node, match_last; | ||
978 | reg_errcode_t ret; | ||
979 | re_dfastate_t **sifted_states; | ||
980 | re_dfastate_t **lim_states = NULL; | ||
981 | re_sift_context_t sctx; | ||
982 | #ifdef DEBUG | ||
983 | assert (mctx->state_log != NULL); | ||
984 | #endif | ||
985 | match_last = mctx->match_last; | ||
986 | halt_node = mctx->last_node; | ||
987 | |||
988 | /* Avoid overflow. */ | ||
989 | if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= match_last, 0)) | ||
990 | return REG_ESPACE; | ||
991 | |||
992 | sifted_states = re_malloc (re_dfastate_t *, match_last + 1); | ||
993 | if (BE (sifted_states == NULL, 0)) | ||
994 | { | ||
995 | ret = REG_ESPACE; | ||
996 | goto free_return; | ||
997 | } | ||
998 | if (dfa->nbackref) | ||
999 | { | ||
1000 | lim_states = re_malloc (re_dfastate_t *, match_last + 1); | ||
1001 | if (BE (lim_states == NULL, 0)) | ||
1002 | { | ||
1003 | ret = REG_ESPACE; | ||
1004 | goto free_return; | ||
1005 | } | ||
1006 | while (1) | ||
1007 | { | ||
1008 | memset (lim_states, '\0', | ||
1009 | sizeof (re_dfastate_t *) * (match_last + 1)); | ||
1010 | sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, | ||
1011 | match_last); | ||
1012 | ret = sift_states_backward (mctx, &sctx); | ||
1013 | re_node_set_free (&sctx.limits); | ||
1014 | if (BE (ret != REG_NOERROR, 0)) | ||
1015 | goto free_return; | ||
1016 | if (sifted_states[0] != NULL || lim_states[0] != NULL) | ||
1017 | break; | ||
1018 | do | ||
1019 | { | ||
1020 | --match_last; | ||
1021 | if (! REG_VALID_INDEX (match_last)) | ||
1022 | { | ||
1023 | ret = REG_NOMATCH; | ||
1024 | goto free_return; | ||
1025 | } | ||
1026 | } while (mctx->state_log[match_last] == NULL | ||
1027 | || !mctx->state_log[match_last]->halt); | ||
1028 | halt_node = check_halt_state_context (mctx, | ||
1029 | mctx->state_log[match_last], | ||
1030 | match_last); | ||
1031 | } | ||
1032 | ret = merge_state_array (dfa, sifted_states, lim_states, | ||
1033 | match_last + 1); | ||
1034 | re_free (lim_states); | ||
1035 | lim_states = NULL; | ||
1036 | if (BE (ret != REG_NOERROR, 0)) | ||
1037 | goto free_return; | ||
1038 | } | ||
1039 | else | ||
1040 | { | ||
1041 | sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last); | ||
1042 | ret = sift_states_backward (mctx, &sctx); | ||
1043 | re_node_set_free (&sctx.limits); | ||
1044 | if (BE (ret != REG_NOERROR, 0)) | ||
1045 | goto free_return; | ||
1046 | } | ||
1047 | re_free (mctx->state_log); | ||
1048 | mctx->state_log = sifted_states; | ||
1049 | sifted_states = NULL; | ||
1050 | mctx->last_node = halt_node; | ||
1051 | mctx->match_last = match_last; | ||
1052 | ret = REG_NOERROR; | ||
1053 | free_return: | ||
1054 | re_free (sifted_states); | ||
1055 | re_free (lim_states); | ||
1056 | return ret; | ||
1057 | } | ||
1058 | |||
1059 | /* Acquire an initial state and return it. | ||
1060 | We must select appropriate initial state depending on the context, | ||
1061 | since initial states may have constraints like "\<", "^", etc.. */ | ||
1062 | |||
1063 | static inline re_dfastate_t * | ||
1064 | __attribute ((always_inline)) internal_function | ||
1065 | acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx, | ||
1066 | Idx idx) | ||
1067 | { | ||
1068 | const re_dfa_t *const dfa = mctx->dfa; | ||
1069 | if (dfa->init_state->has_constraint) | ||
1070 | { | ||
1071 | unsigned int context; | ||
1072 | context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags); | ||
1073 | if (IS_WORD_CONTEXT (context)) | ||
1074 | return dfa->init_state_word; | ||
1075 | else if (IS_ORDINARY_CONTEXT (context)) | ||
1076 | return dfa->init_state; | ||
1077 | else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context)) | ||
1078 | return dfa->init_state_begbuf; | ||
1079 | else if (IS_NEWLINE_CONTEXT (context)) | ||
1080 | return dfa->init_state_nl; | ||
1081 | else if (IS_BEGBUF_CONTEXT (context)) | ||
1082 | { | ||
1083 | /* It is relatively rare case, then calculate on demand. */ | ||
1084 | return re_acquire_state_context (err, dfa, | ||
1085 | dfa->init_state->entrance_nodes, | ||
1086 | context); | ||
1087 | } | ||
1088 | else | ||
1089 | /* Must not happen? */ | ||
1090 | return dfa->init_state; | ||
1091 | } | ||
1092 | else | ||
1093 | return dfa->init_state; | ||
1094 | } | ||
1095 | |||
1096 | /* Check whether the regular expression match input string INPUT or not, | ||
1097 | and return the index where the matching end. Return REG_MISSING if | ||
1098 | there is no match, and return REG_ERROR in case of an error. | ||
1099 | FL_LONGEST_MATCH means we want the POSIX longest matching. | ||
1100 | If P_MATCH_FIRST is not NULL, and the match fails, it is set to the | ||
1101 | next place where we may want to try matching. | ||
1102 | Note that the matcher assume that the maching starts from the current | ||
1103 | index of the buffer. */ | ||
1104 | |||
1105 | static Idx | ||
1106 | internal_function | ||
1107 | check_matching (re_match_context_t *mctx, bool fl_longest_match, | ||
1108 | Idx *p_match_first) | ||
1109 | { | ||
1110 | const re_dfa_t *const dfa = mctx->dfa; | ||
1111 | reg_errcode_t err; | ||
1112 | Idx match = 0; | ||
1113 | Idx match_last = REG_MISSING; | ||
1114 | Idx cur_str_idx = re_string_cur_idx (&mctx->input); | ||
1115 | re_dfastate_t *cur_state; | ||
1116 | bool at_init_state = p_match_first != NULL; | ||
1117 | Idx next_start_idx = cur_str_idx; | ||
1118 | |||
1119 | err = REG_NOERROR; | ||
1120 | cur_state = acquire_init_state_context (&err, mctx, cur_str_idx); | ||
1121 | /* An initial state must not be NULL (invalid). */ | ||
1122 | if (BE (cur_state == NULL, 0)) | ||
1123 | { | ||
1124 | assert (err == REG_ESPACE); | ||
1125 | return REG_ERROR; | ||
1126 | } | ||
1127 | |||
1128 | if (mctx->state_log != NULL) | ||
1129 | { | ||
1130 | mctx->state_log[cur_str_idx] = cur_state; | ||
1131 | |||
1132 | /* Check OP_OPEN_SUBEXP in the initial state in case that we use them | ||
1133 | later. E.g. Processing back references. */ | ||
1134 | if (BE (dfa->nbackref, 0)) | ||
1135 | { | ||
1136 | at_init_state = false; | ||
1137 | err = check_subexp_matching_top (mctx, &cur_state->nodes, 0); | ||
1138 | if (BE (err != REG_NOERROR, 0)) | ||
1139 | return err; | ||
1140 | |||
1141 | if (cur_state->has_backref) | ||
1142 | { | ||
1143 | err = transit_state_bkref (mctx, &cur_state->nodes); | ||
1144 | if (BE (err != REG_NOERROR, 0)) | ||
1145 | return err; | ||
1146 | } | ||
1147 | } | ||
1148 | } | ||
1149 | |||
1150 | /* If the RE accepts NULL string. */ | ||
1151 | if (BE (cur_state->halt, 0)) | ||
1152 | { | ||
1153 | if (!cur_state->has_constraint | ||
1154 | || check_halt_state_context (mctx, cur_state, cur_str_idx)) | ||
1155 | { | ||
1156 | if (!fl_longest_match) | ||
1157 | return cur_str_idx; | ||
1158 | else | ||
1159 | { | ||
1160 | match_last = cur_str_idx; | ||
1161 | match = 1; | ||
1162 | } | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | while (!re_string_eoi (&mctx->input)) | ||
1167 | { | ||
1168 | re_dfastate_t *old_state = cur_state; | ||
1169 | Idx next_char_idx = re_string_cur_idx (&mctx->input) + 1; | ||
1170 | |||
1171 | if (BE (next_char_idx >= mctx->input.bufs_len, 0) | ||
1172 | || (BE (next_char_idx >= mctx->input.valid_len, 0) | ||
1173 | && mctx->input.valid_len < mctx->input.len)) | ||
1174 | { | ||
1175 | err = extend_buffers (mctx); | ||
1176 | if (BE (err != REG_NOERROR, 0)) | ||
1177 | { | ||
1178 | assert (err == REG_ESPACE); | ||
1179 | return REG_ERROR; | ||
1180 | } | ||
1181 | } | ||
1182 | |||
1183 | cur_state = transit_state (&err, mctx, cur_state); | ||
1184 | if (mctx->state_log != NULL) | ||
1185 | cur_state = merge_state_with_log (&err, mctx, cur_state); | ||
1186 | |||
1187 | if (cur_state == NULL) | ||
1188 | { | ||
1189 | /* Reached the invalid state or an error. Try to recover a valid | ||
1190 | state using the state log, if available and if we have not | ||
1191 | already found a valid (even if not the longest) match. */ | ||
1192 | if (BE (err != REG_NOERROR, 0)) | ||
1193 | return REG_ERROR; | ||
1194 | |||
1195 | if (mctx->state_log == NULL | ||
1196 | || (match && !fl_longest_match) | ||
1197 | || (cur_state = find_recover_state (&err, mctx)) == NULL) | ||
1198 | break; | ||
1199 | } | ||
1200 | |||
1201 | if (BE (at_init_state, 0)) | ||
1202 | { | ||
1203 | if (old_state == cur_state) | ||
1204 | next_start_idx = next_char_idx; | ||
1205 | else | ||
1206 | at_init_state = false; | ||
1207 | } | ||
1208 | |||
1209 | if (cur_state->halt) | ||
1210 | { | ||
1211 | /* Reached a halt state. | ||
1212 | Check the halt state can satisfy the current context. */ | ||
1213 | if (!cur_state->has_constraint | ||
1214 | || check_halt_state_context (mctx, cur_state, | ||
1215 | re_string_cur_idx (&mctx->input))) | ||
1216 | { | ||
1217 | /* We found an appropriate halt state. */ | ||
1218 | match_last = re_string_cur_idx (&mctx->input); | ||
1219 | match = 1; | ||
1220 | |||
1221 | /* We found a match, do not modify match_first below. */ | ||
1222 | p_match_first = NULL; | ||
1223 | if (!fl_longest_match) | ||
1224 | break; | ||
1225 | } | ||
1226 | } | ||
1227 | } | ||
1228 | |||
1229 | if (p_match_first) | ||
1230 | *p_match_first += next_start_idx; | ||
1231 | |||
1232 | return match_last; | ||
1233 | } | ||
1234 | |||
1235 | /* Check NODE match the current context. */ | ||
1236 | |||
1237 | static bool | ||
1238 | internal_function | ||
1239 | check_halt_node_context (const re_dfa_t *dfa, Idx node, unsigned int context) | ||
1240 | { | ||
1241 | re_token_type_t type = dfa->nodes[node].type; | ||
1242 | unsigned int constraint = dfa->nodes[node].constraint; | ||
1243 | if (type != END_OF_RE) | ||
1244 | return false; | ||
1245 | if (!constraint) | ||
1246 | return true; | ||
1247 | if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context)) | ||
1248 | return false; | ||
1249 | return true; | ||
1250 | } | ||
1251 | |||
1252 | /* Check the halt state STATE match the current context. | ||
1253 | Return 0 if not match, if the node, STATE has, is a halt node and | ||
1254 | match the context, return the node. */ | ||
1255 | |||
1256 | static Idx | ||
1257 | internal_function | ||
1258 | check_halt_state_context (const re_match_context_t *mctx, | ||
1259 | const re_dfastate_t *state, Idx idx) | ||
1260 | { | ||
1261 | Idx i; | ||
1262 | unsigned int context; | ||
1263 | #ifdef DEBUG | ||
1264 | assert (state->halt); | ||
1265 | #endif | ||
1266 | context = re_string_context_at (&mctx->input, idx, mctx->eflags); | ||
1267 | for (i = 0; i < state->nodes.nelem; ++i) | ||
1268 | if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context)) | ||
1269 | return state->nodes.elems[i]; | ||
1270 | return 0; | ||
1271 | } | ||
1272 | |||
1273 | /* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA | ||
1274 | corresponding to the DFA). | ||
1275 | Return the destination node, and update EPS_VIA_NODES; | ||
1276 | return REG_MISSING in case of errors. */ | ||
1277 | |||
1278 | static Idx | ||
1279 | internal_function | ||
1280 | proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, | ||
1281 | Idx *pidx, Idx node, re_node_set *eps_via_nodes, | ||
1282 | struct re_fail_stack_t *fs) | ||
1283 | { | ||
1284 | const re_dfa_t *const dfa = mctx->dfa; | ||
1285 | Idx i; | ||
1286 | bool ok; | ||
1287 | if (IS_EPSILON_NODE (dfa->nodes[node].type)) | ||
1288 | { | ||
1289 | re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes; | ||
1290 | re_node_set *edests = &dfa->edests[node]; | ||
1291 | Idx dest_node; | ||
1292 | ok = re_node_set_insert (eps_via_nodes, node); | ||
1293 | if (BE (! ok, 0)) | ||
1294 | return REG_ERROR; | ||
1295 | /* Pick up a valid destination, or return REG_MISSING if none | ||
1296 | is found. */ | ||
1297 | for (dest_node = REG_MISSING, i = 0; i < edests->nelem; ++i) | ||
1298 | { | ||
1299 | Idx candidate = edests->elems[i]; | ||
1300 | if (!re_node_set_contains (cur_nodes, candidate)) | ||
1301 | continue; | ||
1302 | if (dest_node == REG_MISSING) | ||
1303 | dest_node = candidate; | ||
1304 | |||
1305 | else | ||
1306 | { | ||
1307 | /* In order to avoid infinite loop like "(a*)*", return the second | ||
1308 | epsilon-transition if the first was already considered. */ | ||
1309 | if (re_node_set_contains (eps_via_nodes, dest_node)) | ||
1310 | return candidate; | ||
1311 | |||
1312 | /* Otherwise, push the second epsilon-transition on the fail stack. */ | ||
1313 | else if (fs != NULL | ||
1314 | && push_fail_stack (fs, *pidx, candidate, nregs, regs, | ||
1315 | eps_via_nodes)) | ||
1316 | return REG_ERROR; | ||
1317 | |||
1318 | /* We know we are going to exit. */ | ||
1319 | break; | ||
1320 | } | ||
1321 | } | ||
1322 | return dest_node; | ||
1323 | } | ||
1324 | else | ||
1325 | { | ||
1326 | Idx naccepted = 0; | ||
1327 | re_token_type_t type = dfa->nodes[node].type; | ||
1328 | |||
1329 | #ifdef RE_ENABLE_I18N | ||
1330 | if (dfa->nodes[node].accept_mb) | ||
1331 | naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx); | ||
1332 | else | ||
1333 | #endif /* RE_ENABLE_I18N */ | ||
1334 | if (type == OP_BACK_REF) | ||
1335 | { | ||
1336 | Idx subexp_idx = dfa->nodes[node].opr.idx + 1; | ||
1337 | naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so; | ||
1338 | if (fs != NULL) | ||
1339 | { | ||
1340 | if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1) | ||
1341 | return REG_MISSING; | ||
1342 | else if (naccepted) | ||
1343 | { | ||
1344 | char *buf = (char *) re_string_get_buffer (&mctx->input); | ||
1345 | if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, | ||
1346 | naccepted) != 0) | ||
1347 | return REG_MISSING; | ||
1348 | } | ||
1349 | } | ||
1350 | |||
1351 | if (naccepted == 0) | ||
1352 | { | ||
1353 | Idx dest_node; | ||
1354 | ok = re_node_set_insert (eps_via_nodes, node); | ||
1355 | if (BE (! ok, 0)) | ||
1356 | return REG_ERROR; | ||
1357 | dest_node = dfa->edests[node].elems[0]; | ||
1358 | if (re_node_set_contains (&mctx->state_log[*pidx]->nodes, | ||
1359 | dest_node)) | ||
1360 | return dest_node; | ||
1361 | } | ||
1362 | } | ||
1363 | |||
1364 | if (naccepted != 0 | ||
1365 | || check_node_accept (mctx, dfa->nodes + node, *pidx)) | ||
1366 | { | ||
1367 | Idx dest_node = dfa->nexts[node]; | ||
1368 | *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted; | ||
1369 | if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL | ||
1370 | || !re_node_set_contains (&mctx->state_log[*pidx]->nodes, | ||
1371 | dest_node))) | ||
1372 | return REG_MISSING; | ||
1373 | re_node_set_empty (eps_via_nodes); | ||
1374 | return dest_node; | ||
1375 | } | ||
1376 | } | ||
1377 | return REG_MISSING; | ||
1378 | } | ||
1379 | |||
1380 | static reg_errcode_t | ||
1381 | internal_function | ||
1382 | push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node, | ||
1383 | Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes) | ||
1384 | { | ||
1385 | reg_errcode_t err; | ||
1386 | Idx num = fs->num++; | ||
1387 | if (fs->num == fs->alloc) | ||
1388 | { | ||
1389 | struct re_fail_stack_ent_t *new_array; | ||
1390 | new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t) | ||
1391 | * fs->alloc * 2)); | ||
1392 | if (new_array == NULL) | ||
1393 | return REG_ESPACE; | ||
1394 | fs->alloc *= 2; | ||
1395 | fs->stack = new_array; | ||
1396 | } | ||
1397 | fs->stack[num].idx = str_idx; | ||
1398 | fs->stack[num].node = dest_node; | ||
1399 | fs->stack[num].regs = re_malloc (regmatch_t, nregs); | ||
1400 | if (fs->stack[num].regs == NULL) | ||
1401 | return REG_ESPACE; | ||
1402 | memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); | ||
1403 | err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); | ||
1404 | return err; | ||
1405 | } | ||
1406 | |||
1407 | static Idx | ||
1408 | internal_function | ||
1409 | pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs, | ||
1410 | regmatch_t *regs, re_node_set *eps_via_nodes) | ||
1411 | { | ||
1412 | Idx num = --fs->num; | ||
1413 | assert (REG_VALID_INDEX (num)); | ||
1414 | *pidx = fs->stack[num].idx; | ||
1415 | memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); | ||
1416 | re_node_set_free (eps_via_nodes); | ||
1417 | re_free (fs->stack[num].regs); | ||
1418 | *eps_via_nodes = fs->stack[num].eps_via_nodes; | ||
1419 | return fs->stack[num].node; | ||
1420 | } | ||
1421 | |||
1422 | /* Set the positions where the subexpressions are starts/ends to registers | ||
1423 | PMATCH. | ||
1424 | Note: We assume that pmatch[0] is already set, and | ||
1425 | pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */ | ||
1426 | |||
1427 | static reg_errcode_t | ||
1428 | internal_function | ||
1429 | set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, | ||
1430 | regmatch_t *pmatch, bool fl_backtrack) | ||
1431 | { | ||
1432 | const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer; | ||
1433 | Idx idx, cur_node; | ||
1434 | re_node_set eps_via_nodes; | ||
1435 | struct re_fail_stack_t *fs; | ||
1436 | struct re_fail_stack_t fs_body = { 0, 2, NULL }; | ||
1437 | regmatch_t *prev_idx_match; | ||
1438 | bool prev_idx_match_malloced = false; | ||
1439 | |||
1440 | #ifdef DEBUG | ||
1441 | assert (nmatch > 1); | ||
1442 | assert (mctx->state_log != NULL); | ||
1443 | #endif | ||
1444 | if (fl_backtrack) | ||
1445 | { | ||
1446 | fs = &fs_body; | ||
1447 | fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc); | ||
1448 | if (fs->stack == NULL) | ||
1449 | return REG_ESPACE; | ||
1450 | } | ||
1451 | else | ||
1452 | fs = NULL; | ||
1453 | |||
1454 | cur_node = dfa->init_node; | ||
1455 | re_node_set_init_empty (&eps_via_nodes); | ||
1456 | |||
1457 | if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) | ||
1458 | prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t)); | ||
1459 | else | ||
1460 | { | ||
1461 | prev_idx_match = re_malloc (regmatch_t, nmatch); | ||
1462 | if (prev_idx_match == NULL) | ||
1463 | { | ||
1464 | free_fail_stack_return (fs); | ||
1465 | return REG_ESPACE; | ||
1466 | } | ||
1467 | prev_idx_match_malloced = true; | ||
1468 | } | ||
1469 | memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); | ||
1470 | |||
1471 | for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) | ||
1472 | { | ||
1473 | update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch); | ||
1474 | |||
1475 | if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) | ||
1476 | { | ||
1477 | Idx reg_idx; | ||
1478 | if (fs) | ||
1479 | { | ||
1480 | for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) | ||
1481 | if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) | ||
1482 | break; | ||
1483 | if (reg_idx == nmatch) | ||
1484 | { | ||
1485 | re_node_set_free (&eps_via_nodes); | ||
1486 | if (prev_idx_match_malloced) | ||
1487 | re_free (prev_idx_match); | ||
1488 | return free_fail_stack_return (fs); | ||
1489 | } | ||
1490 | cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, | ||
1491 | &eps_via_nodes); | ||
1492 | } | ||
1493 | else | ||
1494 | { | ||
1495 | re_node_set_free (&eps_via_nodes); | ||
1496 | if (prev_idx_match_malloced) | ||
1497 | re_free (prev_idx_match); | ||
1498 | return REG_NOERROR; | ||
1499 | } | ||
1500 | } | ||
1501 | |||
1502 | /* Proceed to next node. */ | ||
1503 | cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node, | ||
1504 | &eps_via_nodes, fs); | ||
1505 | |||
1506 | if (BE (! REG_VALID_INDEX (cur_node), 0)) | ||
1507 | { | ||
1508 | if (BE (cur_node == REG_ERROR, 0)) | ||
1509 | { | ||
1510 | re_node_set_free (&eps_via_nodes); | ||
1511 | if (prev_idx_match_malloced) | ||
1512 | re_free (prev_idx_match); | ||
1513 | free_fail_stack_return (fs); | ||
1514 | return REG_ESPACE; | ||
1515 | } | ||
1516 | if (fs) | ||
1517 | cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, | ||
1518 | &eps_via_nodes); | ||
1519 | else | ||
1520 | { | ||
1521 | re_node_set_free (&eps_via_nodes); | ||
1522 | if (prev_idx_match_malloced) | ||
1523 | re_free (prev_idx_match); | ||
1524 | return REG_NOMATCH; | ||
1525 | } | ||
1526 | } | ||
1527 | } | ||
1528 | re_node_set_free (&eps_via_nodes); | ||
1529 | if (prev_idx_match_malloced) | ||
1530 | re_free (prev_idx_match); | ||
1531 | return free_fail_stack_return (fs); | ||
1532 | } | ||
1533 | |||
1534 | static reg_errcode_t | ||
1535 | internal_function | ||
1536 | free_fail_stack_return (struct re_fail_stack_t *fs) | ||
1537 | { | ||
1538 | if (fs) | ||
1539 | { | ||
1540 | Idx fs_idx; | ||
1541 | for (fs_idx = 0; fs_idx < fs->num; ++fs_idx) | ||
1542 | { | ||
1543 | re_node_set_free (&fs->stack[fs_idx].eps_via_nodes); | ||
1544 | re_free (fs->stack[fs_idx].regs); | ||
1545 | } | ||
1546 | re_free (fs->stack); | ||
1547 | } | ||
1548 | return REG_NOERROR; | ||
1549 | } | ||
1550 | |||
1551 | static void | ||
1552 | internal_function | ||
1553 | update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, | ||
1554 | regmatch_t *prev_idx_match, Idx cur_node, Idx cur_idx, Idx nmatch) | ||
1555 | { | ||
1556 | int type = dfa->nodes[cur_node].type; | ||
1557 | if (type == OP_OPEN_SUBEXP) | ||
1558 | { | ||
1559 | Idx reg_num = dfa->nodes[cur_node].opr.idx + 1; | ||
1560 | |||
1561 | /* We are at the first node of this sub expression. */ | ||
1562 | if (reg_num < nmatch) | ||
1563 | { | ||
1564 | pmatch[reg_num].rm_so = cur_idx; | ||
1565 | pmatch[reg_num].rm_eo = -1; | ||
1566 | } | ||
1567 | } | ||
1568 | else if (type == OP_CLOSE_SUBEXP) | ||
1569 | { | ||
1570 | Idx reg_num = dfa->nodes[cur_node].opr.idx + 1; | ||
1571 | if (reg_num < nmatch) | ||
1572 | { | ||
1573 | /* We are at the last node of this sub expression. */ | ||
1574 | if (pmatch[reg_num].rm_so < cur_idx) | ||
1575 | { | ||
1576 | pmatch[reg_num].rm_eo = cur_idx; | ||
1577 | /* This is a non-empty match or we are not inside an optional | ||
1578 | subexpression. Accept this right away. */ | ||
1579 | memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); | ||
1580 | } | ||
1581 | else | ||
1582 | { | ||
1583 | if (dfa->nodes[cur_node].opt_subexp | ||
1584 | && prev_idx_match[reg_num].rm_so != -1) | ||
1585 | /* We transited through an empty match for an optional | ||
1586 | subexpression, like (a?)*, and this is not the subexp's | ||
1587 | first match. Copy back the old content of the registers | ||
1588 | so that matches of an inner subexpression are undone as | ||
1589 | well, like in ((a?))*. */ | ||
1590 | memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch); | ||
1591 | else | ||
1592 | /* We completed a subexpression, but it may be part of | ||
1593 | an optional one, so do not update PREV_IDX_MATCH. */ | ||
1594 | pmatch[reg_num].rm_eo = cur_idx; | ||
1595 | } | ||
1596 | } | ||
1597 | } | ||
1598 | } | ||
1599 | |||
1600 | /* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 | ||
1601 | and sift the nodes in each states according to the following rules. | ||
1602 | Updated state_log will be wrote to STATE_LOG. | ||
1603 | |||
1604 | Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if... | ||
1605 | 1. When STR_IDX == MATCH_LAST(the last index in the state_log): | ||
1606 | If `a' isn't the LAST_NODE and `a' can't epsilon transit to | ||
1607 | the LAST_NODE, we throw away the node `a'. | ||
1608 | 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts | ||
1609 | string `s' and transit to `b': | ||
1610 | i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw | ||
1611 | away the node `a'. | ||
1612 | ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is | ||
1613 | thrown away, we throw away the node `a'. | ||
1614 | 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b': | ||
1615 | i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the | ||
1616 | node `a'. | ||
1617 | ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away, | ||
1618 | we throw away the node `a'. */ | ||
1619 | |||
1620 | #define STATE_NODE_CONTAINS(state,node) \ | ||
1621 | ((state) != NULL && re_node_set_contains (&(state)->nodes, node)) | ||
1622 | |||
1623 | static reg_errcode_t | ||
1624 | internal_function | ||
1625 | sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx) | ||
1626 | { | ||
1627 | reg_errcode_t err; | ||
1628 | int null_cnt = 0; | ||
1629 | Idx str_idx = sctx->last_str_idx; | ||
1630 | re_node_set cur_dest; | ||
1631 | |||
1632 | #ifdef DEBUG | ||
1633 | assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL); | ||
1634 | #endif | ||
1635 | |||
1636 | /* Build sifted state_log[str_idx]. It has the nodes which can epsilon | ||
1637 | transit to the last_node and the last_node itself. */ | ||
1638 | err = re_node_set_init_1 (&cur_dest, sctx->last_node); | ||
1639 | if (BE (err != REG_NOERROR, 0)) | ||
1640 | return err; | ||
1641 | err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); | ||
1642 | if (BE (err != REG_NOERROR, 0)) | ||
1643 | goto free_return; | ||
1644 | |||
1645 | /* Then check each states in the state_log. */ | ||
1646 | while (str_idx > 0) | ||
1647 | { | ||
1648 | /* Update counters. */ | ||
1649 | null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0; | ||
1650 | if (null_cnt > mctx->max_mb_elem_len) | ||
1651 | { | ||
1652 | memset (sctx->sifted_states, '\0', | ||
1653 | sizeof (re_dfastate_t *) * str_idx); | ||
1654 | re_node_set_free (&cur_dest); | ||
1655 | return REG_NOERROR; | ||
1656 | } | ||
1657 | re_node_set_empty (&cur_dest); | ||
1658 | --str_idx; | ||
1659 | |||
1660 | if (mctx->state_log[str_idx]) | ||
1661 | { | ||
1662 | err = build_sifted_states (mctx, sctx, str_idx, &cur_dest); | ||
1663 | if (BE (err != REG_NOERROR, 0)) | ||
1664 | goto free_return; | ||
1665 | } | ||
1666 | |||
1667 | /* Add all the nodes which satisfy the following conditions: | ||
1668 | - It can epsilon transit to a node in CUR_DEST. | ||
1669 | - It is in CUR_SRC. | ||
1670 | And update state_log. */ | ||
1671 | err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); | ||
1672 | if (BE (err != REG_NOERROR, 0)) | ||
1673 | goto free_return; | ||
1674 | } | ||
1675 | err = REG_NOERROR; | ||
1676 | free_return: | ||
1677 | re_node_set_free (&cur_dest); | ||
1678 | return err; | ||
1679 | } | ||
1680 | |||
1681 | static reg_errcode_t | ||
1682 | internal_function | ||
1683 | build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx, | ||
1684 | Idx str_idx, re_node_set *cur_dest) | ||
1685 | { | ||
1686 | const re_dfa_t *const dfa = mctx->dfa; | ||
1687 | const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes; | ||
1688 | Idx i; | ||
1689 | |||
1690 | /* Then build the next sifted state. | ||
1691 | We build the next sifted state on `cur_dest', and update | ||
1692 | `sifted_states[str_idx]' with `cur_dest'. | ||
1693 | Note: | ||
1694 | `cur_dest' is the sifted state from `state_log[str_idx + 1]'. | ||
1695 | `cur_src' points the node_set of the old `state_log[str_idx]' | ||
1696 | (with the epsilon nodes pre-filtered out). */ | ||
1697 | for (i = 0; i < cur_src->nelem; i++) | ||
1698 | { | ||
1699 | Idx prev_node = cur_src->elems[i]; | ||
1700 | int naccepted = 0; | ||
1701 | bool ok; | ||
1702 | |||
1703 | #ifdef DEBUG | ||
1704 | re_token_type_t type = dfa->nodes[prev_node].type; | ||
1705 | assert (!IS_EPSILON_NODE (type)); | ||
1706 | #endif | ||
1707 | #ifdef RE_ENABLE_I18N | ||
1708 | /* If the node may accept `multi byte'. */ | ||
1709 | if (dfa->nodes[prev_node].accept_mb) | ||
1710 | naccepted = sift_states_iter_mb (mctx, sctx, prev_node, | ||
1711 | str_idx, sctx->last_str_idx); | ||
1712 | #endif /* RE_ENABLE_I18N */ | ||
1713 | |||
1714 | /* We don't check backreferences here. | ||
1715 | See update_cur_sifted_state(). */ | ||
1716 | if (!naccepted | ||
1717 | && check_node_accept (mctx, dfa->nodes + prev_node, str_idx) | ||
1718 | && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1], | ||
1719 | dfa->nexts[prev_node])) | ||
1720 | naccepted = 1; | ||
1721 | |||
1722 | if (naccepted == 0) | ||
1723 | continue; | ||
1724 | |||
1725 | if (sctx->limits.nelem) | ||
1726 | { | ||
1727 | Idx to_idx = str_idx + naccepted; | ||
1728 | if (check_dst_limits (mctx, &sctx->limits, | ||
1729 | dfa->nexts[prev_node], to_idx, | ||
1730 | prev_node, str_idx)) | ||
1731 | continue; | ||
1732 | } | ||
1733 | ok = re_node_set_insert (cur_dest, prev_node); | ||
1734 | if (BE (! ok, 0)) | ||
1735 | return REG_ESPACE; | ||
1736 | } | ||
1737 | |||
1738 | return REG_NOERROR; | ||
1739 | } | ||
1740 | |||
1741 | /* Helper functions. */ | ||
1742 | |||
1743 | static reg_errcode_t | ||
1744 | internal_function | ||
1745 | clean_state_log_if_needed (re_match_context_t *mctx, Idx next_state_log_idx) | ||
1746 | { | ||
1747 | Idx top = mctx->state_log_top; | ||
1748 | |||
1749 | if (next_state_log_idx >= mctx->input.bufs_len | ||
1750 | || (next_state_log_idx >= mctx->input.valid_len | ||
1751 | && mctx->input.valid_len < mctx->input.len)) | ||
1752 | { | ||
1753 | reg_errcode_t err; | ||
1754 | err = extend_buffers (mctx); | ||
1755 | if (BE (err != REG_NOERROR, 0)) | ||
1756 | return err; | ||
1757 | } | ||
1758 | |||
1759 | if (top < next_state_log_idx) | ||
1760 | { | ||
1761 | memset (mctx->state_log + top + 1, '\0', | ||
1762 | sizeof (re_dfastate_t *) * (next_state_log_idx - top)); | ||
1763 | mctx->state_log_top = next_state_log_idx; | ||
1764 | } | ||
1765 | return REG_NOERROR; | ||
1766 | } | ||
1767 | |||
1768 | static reg_errcode_t | ||
1769 | internal_function | ||
1770 | merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst, | ||
1771 | re_dfastate_t **src, Idx num) | ||
1772 | { | ||
1773 | Idx st_idx; | ||
1774 | reg_errcode_t err; | ||
1775 | for (st_idx = 0; st_idx < num; ++st_idx) | ||
1776 | { | ||
1777 | if (dst[st_idx] == NULL) | ||
1778 | dst[st_idx] = src[st_idx]; | ||
1779 | else if (src[st_idx] != NULL) | ||
1780 | { | ||
1781 | re_node_set merged_set; | ||
1782 | err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes, | ||
1783 | &src[st_idx]->nodes); | ||
1784 | if (BE (err != REG_NOERROR, 0)) | ||
1785 | return err; | ||
1786 | dst[st_idx] = re_acquire_state (&err, dfa, &merged_set); | ||
1787 | re_node_set_free (&merged_set); | ||
1788 | if (BE (err != REG_NOERROR, 0)) | ||
1789 | return err; | ||
1790 | } | ||
1791 | } | ||
1792 | return REG_NOERROR; | ||
1793 | } | ||
1794 | |||
1795 | static reg_errcode_t | ||
1796 | internal_function | ||
1797 | update_cur_sifted_state (const re_match_context_t *mctx, | ||
1798 | re_sift_context_t *sctx, Idx str_idx, | ||
1799 | re_node_set *dest_nodes) | ||
1800 | { | ||
1801 | const re_dfa_t *const dfa = mctx->dfa; | ||
1802 | reg_errcode_t err = REG_NOERROR; | ||
1803 | const re_node_set *candidates; | ||
1804 | candidates = ((mctx->state_log[str_idx] == NULL) ? NULL | ||
1805 | : &mctx->state_log[str_idx]->nodes); | ||
1806 | |||
1807 | if (dest_nodes->nelem == 0) | ||
1808 | sctx->sifted_states[str_idx] = NULL; | ||
1809 | else | ||
1810 | { | ||
1811 | if (candidates) | ||
1812 | { | ||
1813 | /* At first, add the nodes which can epsilon transit to a node in | ||
1814 | DEST_NODE. */ | ||
1815 | err = add_epsilon_src_nodes (dfa, dest_nodes, candidates); | ||
1816 | if (BE (err != REG_NOERROR, 0)) | ||
1817 | return err; | ||
1818 | |||
1819 | /* Then, check the limitations in the current sift_context. */ | ||
1820 | if (sctx->limits.nelem) | ||
1821 | { | ||
1822 | err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits, | ||
1823 | mctx->bkref_ents, str_idx); | ||
1824 | if (BE (err != REG_NOERROR, 0)) | ||
1825 | return err; | ||
1826 | } | ||
1827 | } | ||
1828 | |||
1829 | sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes); | ||
1830 | if (BE (err != REG_NOERROR, 0)) | ||
1831 | return err; | ||
1832 | } | ||
1833 | |||
1834 | if (candidates && mctx->state_log[str_idx]->has_backref) | ||
1835 | { | ||
1836 | err = sift_states_bkref (mctx, sctx, str_idx, candidates); | ||
1837 | if (BE (err != REG_NOERROR, 0)) | ||
1838 | return err; | ||
1839 | } | ||
1840 | return REG_NOERROR; | ||
1841 | } | ||
1842 | |||
1843 | static reg_errcode_t | ||
1844 | internal_function | ||
1845 | add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, | ||
1846 | const re_node_set *candidates) | ||
1847 | { | ||
1848 | reg_errcode_t err = REG_NOERROR; | ||
1849 | Idx i; | ||
1850 | |||
1851 | re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes); | ||
1852 | if (BE (err != REG_NOERROR, 0)) | ||
1853 | return err; | ||
1854 | |||
1855 | if (!state->inveclosure.alloc) | ||
1856 | { | ||
1857 | err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem); | ||
1858 | if (BE (err != REG_NOERROR, 0)) | ||
1859 | return REG_ESPACE; | ||
1860 | for (i = 0; i < dest_nodes->nelem; i++) | ||
1861 | re_node_set_merge (&state->inveclosure, | ||
1862 | dfa->inveclosures + dest_nodes->elems[i]); | ||
1863 | } | ||
1864 | return re_node_set_add_intersect (dest_nodes, candidates, | ||
1865 | &state->inveclosure); | ||
1866 | } | ||
1867 | |||
1868 | static reg_errcode_t | ||
1869 | internal_function | ||
1870 | sub_epsilon_src_nodes (const re_dfa_t *dfa, Idx node, re_node_set *dest_nodes, | ||
1871 | const re_node_set *candidates) | ||
1872 | { | ||
1873 | Idx ecl_idx; | ||
1874 | reg_errcode_t err; | ||
1875 | re_node_set *inv_eclosure = dfa->inveclosures + node; | ||
1876 | re_node_set except_nodes; | ||
1877 | re_node_set_init_empty (&except_nodes); | ||
1878 | for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) | ||
1879 | { | ||
1880 | Idx cur_node = inv_eclosure->elems[ecl_idx]; | ||
1881 | if (cur_node == node) | ||
1882 | continue; | ||
1883 | if (IS_EPSILON_NODE (dfa->nodes[cur_node].type)) | ||
1884 | { | ||
1885 | Idx edst1 = dfa->edests[cur_node].elems[0]; | ||
1886 | Idx edst2 = ((dfa->edests[cur_node].nelem > 1) | ||
1887 | ? dfa->edests[cur_node].elems[1] : REG_MISSING); | ||
1888 | if ((!re_node_set_contains (inv_eclosure, edst1) | ||
1889 | && re_node_set_contains (dest_nodes, edst1)) | ||
1890 | || (REG_VALID_NONZERO_INDEX (edst2) | ||
1891 | && !re_node_set_contains (inv_eclosure, edst2) | ||
1892 | && re_node_set_contains (dest_nodes, edst2))) | ||
1893 | { | ||
1894 | err = re_node_set_add_intersect (&except_nodes, candidates, | ||
1895 | dfa->inveclosures + cur_node); | ||
1896 | if (BE (err != REG_NOERROR, 0)) | ||
1897 | { | ||
1898 | re_node_set_free (&except_nodes); | ||
1899 | return err; | ||
1900 | } | ||
1901 | } | ||
1902 | } | ||
1903 | } | ||
1904 | for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) | ||
1905 | { | ||
1906 | Idx cur_node = inv_eclosure->elems[ecl_idx]; | ||
1907 | if (!re_node_set_contains (&except_nodes, cur_node)) | ||
1908 | { | ||
1909 | Idx idx = re_node_set_contains (dest_nodes, cur_node) - 1; | ||
1910 | re_node_set_remove_at (dest_nodes, idx); | ||
1911 | } | ||
1912 | } | ||
1913 | re_node_set_free (&except_nodes); | ||
1914 | return REG_NOERROR; | ||
1915 | } | ||
1916 | |||
1917 | static bool | ||
1918 | internal_function | ||
1919 | check_dst_limits (const re_match_context_t *mctx, const re_node_set *limits, | ||
1920 | Idx dst_node, Idx dst_idx, Idx src_node, Idx src_idx) | ||
1921 | { | ||
1922 | const re_dfa_t *const dfa = mctx->dfa; | ||
1923 | Idx lim_idx, src_pos, dst_pos; | ||
1924 | |||
1925 | Idx dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx); | ||
1926 | Idx src_bkref_idx = search_cur_bkref_entry (mctx, src_idx); | ||
1927 | for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) | ||
1928 | { | ||
1929 | Idx subexp_idx; | ||
1930 | struct re_backref_cache_entry *ent; | ||
1931 | ent = mctx->bkref_ents + limits->elems[lim_idx]; | ||
1932 | subexp_idx = dfa->nodes[ent->node].opr.idx; | ||
1933 | |||
1934 | dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], | ||
1935 | subexp_idx, dst_node, dst_idx, | ||
1936 | dst_bkref_idx); | ||
1937 | src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], | ||
1938 | subexp_idx, src_node, src_idx, | ||
1939 | src_bkref_idx); | ||
1940 | |||
1941 | /* In case of: | ||
1942 | <src> <dst> ( <subexp> ) | ||
1943 | ( <subexp> ) <src> <dst> | ||
1944 | ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */ | ||
1945 | if (src_pos == dst_pos) | ||
1946 | continue; /* This is unrelated limitation. */ | ||
1947 | else | ||
1948 | return true; | ||
1949 | } | ||
1950 | return false; | ||
1951 | } | ||
1952 | |||
1953 | static int | ||
1954 | internal_function | ||
1955 | check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries, | ||
1956 | Idx subexp_idx, Idx from_node, Idx bkref_idx) | ||
1957 | { | ||
1958 | const re_dfa_t *const dfa = mctx->dfa; | ||
1959 | const re_node_set *eclosures = dfa->eclosures + from_node; | ||
1960 | Idx node_idx; | ||
1961 | |||
1962 | /* Else, we are on the boundary: examine the nodes on the epsilon | ||
1963 | closure. */ | ||
1964 | for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx) | ||
1965 | { | ||
1966 | Idx node = eclosures->elems[node_idx]; | ||
1967 | switch (dfa->nodes[node].type) | ||
1968 | { | ||
1969 | case OP_BACK_REF: | ||
1970 | if (bkref_idx != REG_MISSING) | ||
1971 | { | ||
1972 | struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx; | ||
1973 | do | ||
1974 | { | ||
1975 | Idx dst; | ||
1976 | int cpos; | ||
1977 | |||
1978 | if (ent->node != node) | ||
1979 | continue; | ||
1980 | |||
1981 | if (subexp_idx < BITSET_WORD_BITS | ||
1982 | && !(ent->eps_reachable_subexps_map | ||
1983 | & ((bitset_word_t) 1 << subexp_idx))) | ||
1984 | continue; | ||
1985 | |||
1986 | /* Recurse trying to reach the OP_OPEN_SUBEXP and | ||
1987 | OP_CLOSE_SUBEXP cases below. But, if the | ||
1988 | destination node is the same node as the source | ||
1989 | node, don't recurse because it would cause an | ||
1990 | infinite loop: a regex that exhibits this behavior | ||
1991 | is ()\1*\1* */ | ||
1992 | dst = dfa->edests[node].elems[0]; | ||
1993 | if (dst == from_node) | ||
1994 | { | ||
1995 | if (boundaries & 1) | ||
1996 | return -1; | ||
1997 | else /* if (boundaries & 2) */ | ||
1998 | return 0; | ||
1999 | } | ||
2000 | |||
2001 | cpos = | ||
2002 | check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, | ||
2003 | dst, bkref_idx); | ||
2004 | if (cpos == -1 /* && (boundaries & 1) */) | ||
2005 | return -1; | ||
2006 | if (cpos == 0 && (boundaries & 2)) | ||
2007 | return 0; | ||
2008 | |||
2009 | if (subexp_idx < BITSET_WORD_BITS) | ||
2010 | ent->eps_reachable_subexps_map | ||
2011 | &= ~((bitset_word_t) 1 << subexp_idx); | ||
2012 | } | ||
2013 | while (ent++->more); | ||
2014 | } | ||
2015 | break; | ||
2016 | |||
2017 | case OP_OPEN_SUBEXP: | ||
2018 | if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx) | ||
2019 | return -1; | ||
2020 | break; | ||
2021 | |||
2022 | case OP_CLOSE_SUBEXP: | ||
2023 | if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx) | ||
2024 | return 0; | ||
2025 | break; | ||
2026 | |||
2027 | default: | ||
2028 | break; | ||
2029 | } | ||
2030 | } | ||
2031 | |||
2032 | return (boundaries & 2) ? 1 : 0; | ||
2033 | } | ||
2034 | |||
2035 | static int | ||
2036 | internal_function | ||
2037 | check_dst_limits_calc_pos (const re_match_context_t *mctx, Idx limit, | ||
2038 | Idx subexp_idx, Idx from_node, Idx str_idx, | ||
2039 | Idx bkref_idx) | ||
2040 | { | ||
2041 | struct re_backref_cache_entry *lim = mctx->bkref_ents + limit; | ||
2042 | int boundaries; | ||
2043 | |||
2044 | /* If we are outside the range of the subexpression, return -1 or 1. */ | ||
2045 | if (str_idx < lim->subexp_from) | ||
2046 | return -1; | ||
2047 | |||
2048 | if (lim->subexp_to < str_idx) | ||
2049 | return 1; | ||
2050 | |||
2051 | /* If we are within the subexpression, return 0. */ | ||
2052 | boundaries = (str_idx == lim->subexp_from); | ||
2053 | boundaries |= (str_idx == lim->subexp_to) << 1; | ||
2054 | if (boundaries == 0) | ||
2055 | return 0; | ||
2056 | |||
2057 | /* Else, examine epsilon closure. */ | ||
2058 | return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, | ||
2059 | from_node, bkref_idx); | ||
2060 | } | ||
2061 | |||
2062 | /* Check the limitations of sub expressions LIMITS, and remove the nodes | ||
2063 | which are against limitations from DEST_NODES. */ | ||
2064 | |||
2065 | static reg_errcode_t | ||
2066 | internal_function | ||
2067 | check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes, | ||
2068 | const re_node_set *candidates, re_node_set *limits, | ||
2069 | struct re_backref_cache_entry *bkref_ents, Idx str_idx) | ||
2070 | { | ||
2071 | reg_errcode_t err; | ||
2072 | Idx node_idx, lim_idx; | ||
2073 | |||
2074 | for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) | ||
2075 | { | ||
2076 | Idx subexp_idx; | ||
2077 | struct re_backref_cache_entry *ent; | ||
2078 | ent = bkref_ents + limits->elems[lim_idx]; | ||
2079 | |||
2080 | if (str_idx <= ent->subexp_from || ent->str_idx < str_idx) | ||
2081 | continue; /* This is unrelated limitation. */ | ||
2082 | |||
2083 | subexp_idx = dfa->nodes[ent->node].opr.idx; | ||
2084 | if (ent->subexp_to == str_idx) | ||
2085 | { | ||
2086 | Idx ops_node = REG_MISSING; | ||
2087 | Idx cls_node = REG_MISSING; | ||
2088 | for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) | ||
2089 | { | ||
2090 | Idx node = dest_nodes->elems[node_idx]; | ||
2091 | re_token_type_t type = dfa->nodes[node].type; | ||
2092 | if (type == OP_OPEN_SUBEXP | ||
2093 | && subexp_idx == dfa->nodes[node].opr.idx) | ||
2094 | ops_node = node; | ||
2095 | else if (type == OP_CLOSE_SUBEXP | ||
2096 | && subexp_idx == dfa->nodes[node].opr.idx) | ||
2097 | cls_node = node; | ||
2098 | } | ||
2099 | |||
2100 | /* Check the limitation of the open subexpression. */ | ||
2101 | /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */ | ||
2102 | if (REG_VALID_INDEX (ops_node)) | ||
2103 | { | ||
2104 | err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes, | ||
2105 | candidates); | ||
2106 | if (BE (err != REG_NOERROR, 0)) | ||
2107 | return err; | ||
2108 | } | ||
2109 | |||
2110 | /* Check the limitation of the close subexpression. */ | ||
2111 | if (REG_VALID_INDEX (cls_node)) | ||
2112 | for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) | ||
2113 | { | ||
2114 | Idx node = dest_nodes->elems[node_idx]; | ||
2115 | if (!re_node_set_contains (dfa->inveclosures + node, | ||
2116 | cls_node) | ||
2117 | && !re_node_set_contains (dfa->eclosures + node, | ||
2118 | cls_node)) | ||
2119 | { | ||
2120 | /* It is against this limitation. | ||
2121 | Remove it form the current sifted state. */ | ||
2122 | err = sub_epsilon_src_nodes (dfa, node, dest_nodes, | ||
2123 | candidates); | ||
2124 | if (BE (err != REG_NOERROR, 0)) | ||
2125 | return err; | ||
2126 | --node_idx; | ||
2127 | } | ||
2128 | } | ||
2129 | } | ||
2130 | else /* (ent->subexp_to != str_idx) */ | ||
2131 | { | ||
2132 | for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) | ||
2133 | { | ||
2134 | Idx node = dest_nodes->elems[node_idx]; | ||
2135 | re_token_type_t type = dfa->nodes[node].type; | ||
2136 | if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP) | ||
2137 | { | ||
2138 | if (subexp_idx != dfa->nodes[node].opr.idx) | ||
2139 | continue; | ||
2140 | /* It is against this limitation. | ||
2141 | Remove it form the current sifted state. */ | ||
2142 | err = sub_epsilon_src_nodes (dfa, node, dest_nodes, | ||
2143 | candidates); | ||
2144 | if (BE (err != REG_NOERROR, 0)) | ||
2145 | return err; | ||
2146 | } | ||
2147 | } | ||
2148 | } | ||
2149 | } | ||
2150 | return REG_NOERROR; | ||
2151 | } | ||
2152 | |||
2153 | static reg_errcode_t | ||
2154 | internal_function | ||
2155 | sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx, | ||
2156 | Idx str_idx, const re_node_set *candidates) | ||
2157 | { | ||
2158 | const re_dfa_t *const dfa = mctx->dfa; | ||
2159 | reg_errcode_t err; | ||
2160 | Idx node_idx, node; | ||
2161 | re_sift_context_t local_sctx; | ||
2162 | Idx first_idx = search_cur_bkref_entry (mctx, str_idx); | ||
2163 | |||
2164 | if (first_idx == REG_MISSING) | ||
2165 | return REG_NOERROR; | ||
2166 | |||
2167 | local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */ | ||
2168 | |||
2169 | for (node_idx = 0; node_idx < candidates->nelem; ++node_idx) | ||
2170 | { | ||
2171 | Idx enabled_idx; | ||
2172 | re_token_type_t type; | ||
2173 | struct re_backref_cache_entry *entry; | ||
2174 | node = candidates->elems[node_idx]; | ||
2175 | type = dfa->nodes[node].type; | ||
2176 | /* Avoid infinite loop for the REs like "()\1+". */ | ||
2177 | if (node == sctx->last_node && str_idx == sctx->last_str_idx) | ||
2178 | continue; | ||
2179 | if (type != OP_BACK_REF) | ||
2180 | continue; | ||
2181 | |||
2182 | entry = mctx->bkref_ents + first_idx; | ||
2183 | enabled_idx = first_idx; | ||
2184 | do | ||
2185 | { | ||
2186 | Idx subexp_len; | ||
2187 | Idx to_idx; | ||
2188 | Idx dst_node; | ||
2189 | bool ok; | ||
2190 | re_dfastate_t *cur_state; | ||
2191 | |||
2192 | if (entry->node != node) | ||
2193 | continue; | ||
2194 | subexp_len = entry->subexp_to - entry->subexp_from; | ||
2195 | to_idx = str_idx + subexp_len; | ||
2196 | dst_node = (subexp_len ? dfa->nexts[node] | ||
2197 | : dfa->edests[node].elems[0]); | ||
2198 | |||
2199 | if (to_idx > sctx->last_str_idx | ||
2200 | || sctx->sifted_states[to_idx] == NULL | ||
2201 | || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node) | ||
2202 | || check_dst_limits (mctx, &sctx->limits, node, | ||
2203 | str_idx, dst_node, to_idx)) | ||
2204 | continue; | ||
2205 | |||
2206 | if (local_sctx.sifted_states == NULL) | ||
2207 | { | ||
2208 | local_sctx = *sctx; | ||
2209 | err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits); | ||
2210 | if (BE (err != REG_NOERROR, 0)) | ||
2211 | goto free_return; | ||
2212 | } | ||
2213 | local_sctx.last_node = node; | ||
2214 | local_sctx.last_str_idx = str_idx; | ||
2215 | ok = re_node_set_insert (&local_sctx.limits, enabled_idx); | ||
2216 | if (BE (! ok, 0)) | ||
2217 | { | ||
2218 | err = REG_ESPACE; | ||
2219 | goto free_return; | ||
2220 | } | ||
2221 | cur_state = local_sctx.sifted_states[str_idx]; | ||
2222 | err = sift_states_backward (mctx, &local_sctx); | ||
2223 | if (BE (err != REG_NOERROR, 0)) | ||
2224 | goto free_return; | ||
2225 | if (sctx->limited_states != NULL) | ||
2226 | { | ||
2227 | err = merge_state_array (dfa, sctx->limited_states, | ||
2228 | local_sctx.sifted_states, | ||
2229 | str_idx + 1); | ||
2230 | if (BE (err != REG_NOERROR, 0)) | ||
2231 | goto free_return; | ||
2232 | } | ||
2233 | local_sctx.sifted_states[str_idx] = cur_state; | ||
2234 | re_node_set_remove (&local_sctx.limits, enabled_idx); | ||
2235 | |||
2236 | /* mctx->bkref_ents may have changed, reload the pointer. */ | ||
2237 | entry = mctx->bkref_ents + enabled_idx; | ||
2238 | } | ||
2239 | while (enabled_idx++, entry++->more); | ||
2240 | } | ||
2241 | err = REG_NOERROR; | ||
2242 | free_return: | ||
2243 | if (local_sctx.sifted_states != NULL) | ||
2244 | { | ||
2245 | re_node_set_free (&local_sctx.limits); | ||
2246 | } | ||
2247 | |||
2248 | return err; | ||
2249 | } | ||
2250 | |||
2251 | |||
2252 | #ifdef RE_ENABLE_I18N | ||
2253 | static int | ||
2254 | internal_function | ||
2255 | sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx, | ||
2256 | Idx node_idx, Idx str_idx, Idx max_str_idx) | ||
2257 | { | ||
2258 | const re_dfa_t *const dfa = mctx->dfa; | ||
2259 | int naccepted; | ||
2260 | /* Check the node can accept `multi byte'. */ | ||
2261 | naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx); | ||
2262 | if (naccepted > 0 && str_idx + naccepted <= max_str_idx && | ||
2263 | !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted], | ||
2264 | dfa->nexts[node_idx])) | ||
2265 | /* The node can't accept the `multi byte', or the | ||
2266 | destination was already thrown away, then the node | ||
2267 | could't accept the current input `multi byte'. */ | ||
2268 | naccepted = 0; | ||
2269 | /* Otherwise, it is sure that the node could accept | ||
2270 | `naccepted' bytes input. */ | ||
2271 | return naccepted; | ||
2272 | } | ||
2273 | #endif /* RE_ENABLE_I18N */ | ||
2274 | |||
2275 | |||
2276 | /* Functions for state transition. */ | ||
2277 | |||
2278 | /* Return the next state to which the current state STATE will transit by | ||
2279 | accepting the current input byte, and update STATE_LOG if necessary. | ||
2280 | If STATE can accept a multibyte char/collating element/back reference | ||
2281 | update the destination of STATE_LOG. */ | ||
2282 | |||
2283 | static re_dfastate_t * | ||
2284 | internal_function | ||
2285 | transit_state (reg_errcode_t *err, re_match_context_t *mctx, | ||
2286 | re_dfastate_t *state) | ||
2287 | { | ||
2288 | re_dfastate_t **trtable; | ||
2289 | unsigned char ch; | ||
2290 | |||
2291 | #ifdef RE_ENABLE_I18N | ||
2292 | /* If the current state can accept multibyte. */ | ||
2293 | if (BE (state->accept_mb, 0)) | ||
2294 | { | ||
2295 | *err = transit_state_mb (mctx, state); | ||
2296 | if (BE (*err != REG_NOERROR, 0)) | ||
2297 | return NULL; | ||
2298 | } | ||
2299 | #endif /* RE_ENABLE_I18N */ | ||
2300 | |||
2301 | /* Then decide the next state with the single byte. */ | ||
2302 | #if 0 | ||
2303 | if (0) | ||
2304 | /* don't use transition table */ | ||
2305 | return transit_state_sb (err, mctx, state); | ||
2306 | #endif | ||
2307 | |||
2308 | /* Use transition table */ | ||
2309 | ch = re_string_fetch_byte (&mctx->input); | ||
2310 | for (;;) | ||
2311 | { | ||
2312 | trtable = state->trtable; | ||
2313 | if (BE (trtable != NULL, 1)) | ||
2314 | return trtable[ch]; | ||
2315 | |||
2316 | trtable = state->word_trtable; | ||
2317 | if (BE (trtable != NULL, 1)) | ||
2318 | { | ||
2319 | unsigned int context; | ||
2320 | context | ||
2321 | = re_string_context_at (&mctx->input, | ||
2322 | re_string_cur_idx (&mctx->input) - 1, | ||
2323 | mctx->eflags); | ||
2324 | if (IS_WORD_CONTEXT (context)) | ||
2325 | return trtable[ch + SBC_MAX]; | ||
2326 | else | ||
2327 | return trtable[ch]; | ||
2328 | } | ||
2329 | |||
2330 | if (!build_trtable (mctx->dfa, state)) | ||
2331 | { | ||
2332 | *err = REG_ESPACE; | ||
2333 | return NULL; | ||
2334 | } | ||
2335 | |||
2336 | /* Retry, we now have a transition table. */ | ||
2337 | } | ||
2338 | } | ||
2339 | |||
2340 | /* Update the state_log if we need */ | ||
2341 | re_dfastate_t * | ||
2342 | internal_function | ||
2343 | merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx, | ||
2344 | re_dfastate_t *next_state) | ||
2345 | { | ||
2346 | const re_dfa_t *const dfa = mctx->dfa; | ||
2347 | Idx cur_idx = re_string_cur_idx (&mctx->input); | ||
2348 | |||
2349 | if (cur_idx > mctx->state_log_top) | ||
2350 | { | ||
2351 | mctx->state_log[cur_idx] = next_state; | ||
2352 | mctx->state_log_top = cur_idx; | ||
2353 | } | ||
2354 | else if (mctx->state_log[cur_idx] == 0) | ||
2355 | { | ||
2356 | mctx->state_log[cur_idx] = next_state; | ||
2357 | } | ||
2358 | else | ||
2359 | { | ||
2360 | re_dfastate_t *pstate; | ||
2361 | unsigned int context; | ||
2362 | re_node_set next_nodes, *log_nodes, *table_nodes = NULL; | ||
2363 | /* If (state_log[cur_idx] != 0), it implies that cur_idx is | ||
2364 | the destination of a multibyte char/collating element/ | ||
2365 | back reference. Then the next state is the union set of | ||
2366 | these destinations and the results of the transition table. */ | ||
2367 | pstate = mctx->state_log[cur_idx]; | ||
2368 | log_nodes = pstate->entrance_nodes; | ||
2369 | if (next_state != NULL) | ||
2370 | { | ||
2371 | table_nodes = next_state->entrance_nodes; | ||
2372 | *err = re_node_set_init_union (&next_nodes, table_nodes, | ||
2373 | log_nodes); | ||
2374 | if (BE (*err != REG_NOERROR, 0)) | ||
2375 | return NULL; | ||
2376 | } | ||
2377 | else | ||
2378 | next_nodes = *log_nodes; | ||
2379 | /* Note: We already add the nodes of the initial state, | ||
2380 | then we don't need to add them here. */ | ||
2381 | |||
2382 | context = re_string_context_at (&mctx->input, | ||
2383 | re_string_cur_idx (&mctx->input) - 1, | ||
2384 | mctx->eflags); | ||
2385 | next_state = mctx->state_log[cur_idx] | ||
2386 | = re_acquire_state_context (err, dfa, &next_nodes, context); | ||
2387 | /* We don't need to check errors here, since the return value of | ||
2388 | this function is next_state and ERR is already set. */ | ||
2389 | |||
2390 | if (table_nodes != NULL) | ||
2391 | re_node_set_free (&next_nodes); | ||
2392 | } | ||
2393 | |||
2394 | if (BE (dfa->nbackref, 0) && next_state != NULL) | ||
2395 | { | ||
2396 | /* Check OP_OPEN_SUBEXP in the current state in case that we use them | ||
2397 | later. We must check them here, since the back references in the | ||
2398 | next state might use them. */ | ||
2399 | *err = check_subexp_matching_top (mctx, &next_state->nodes, | ||
2400 | cur_idx); | ||
2401 | if (BE (*err != REG_NOERROR, 0)) | ||
2402 | return NULL; | ||
2403 | |||
2404 | /* If the next state has back references. */ | ||
2405 | if (next_state->has_backref) | ||
2406 | { | ||
2407 | *err = transit_state_bkref (mctx, &next_state->nodes); | ||
2408 | if (BE (*err != REG_NOERROR, 0)) | ||
2409 | return NULL; | ||
2410 | next_state = mctx->state_log[cur_idx]; | ||
2411 | } | ||
2412 | } | ||
2413 | |||
2414 | return next_state; | ||
2415 | } | ||
2416 | |||
2417 | /* Skip bytes in the input that correspond to part of a | ||
2418 | multi-byte match, then look in the log for a state | ||
2419 | from which to restart matching. */ | ||
2420 | static re_dfastate_t * | ||
2421 | internal_function | ||
2422 | find_recover_state (reg_errcode_t *err, re_match_context_t *mctx) | ||
2423 | { | ||
2424 | re_dfastate_t *cur_state; | ||
2425 | do | ||
2426 | { | ||
2427 | Idx max = mctx->state_log_top; | ||
2428 | Idx cur_str_idx = re_string_cur_idx (&mctx->input); | ||
2429 | |||
2430 | do | ||
2431 | { | ||
2432 | if (++cur_str_idx > max) | ||
2433 | return NULL; | ||
2434 | re_string_skip_bytes (&mctx->input, 1); | ||
2435 | } | ||
2436 | while (mctx->state_log[cur_str_idx] == NULL); | ||
2437 | |||
2438 | cur_state = merge_state_with_log (err, mctx, NULL); | ||
2439 | } | ||
2440 | while (*err == REG_NOERROR && cur_state == NULL); | ||
2441 | return cur_state; | ||
2442 | } | ||
2443 | |||
2444 | /* Helper functions for transit_state. */ | ||
2445 | |||
2446 | /* From the node set CUR_NODES, pick up the nodes whose types are | ||
2447 | OP_OPEN_SUBEXP and which have corresponding back references in the regular | ||
2448 | expression. And register them to use them later for evaluating the | ||
2449 | correspoding back references. */ | ||
2450 | |||
2451 | static reg_errcode_t | ||
2452 | internal_function | ||
2453 | check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes, | ||
2454 | Idx str_idx) | ||
2455 | { | ||
2456 | const re_dfa_t *const dfa = mctx->dfa; | ||
2457 | Idx node_idx; | ||
2458 | reg_errcode_t err; | ||
2459 | |||
2460 | /* TODO: This isn't efficient. | ||
2461 | Because there might be more than one nodes whose types are | ||
2462 | OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all | ||
2463 | nodes. | ||
2464 | E.g. RE: (a){2} */ | ||
2465 | for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx) | ||
2466 | { | ||
2467 | Idx node = cur_nodes->elems[node_idx]; | ||
2468 | if (dfa->nodes[node].type == OP_OPEN_SUBEXP | ||
2469 | && dfa->nodes[node].opr.idx < BITSET_WORD_BITS | ||
2470 | && (dfa->used_bkref_map | ||
2471 | & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx))) | ||
2472 | { | ||
2473 | err = match_ctx_add_subtop (mctx, node, str_idx); | ||
2474 | if (BE (err != REG_NOERROR, 0)) | ||
2475 | return err; | ||
2476 | } | ||
2477 | } | ||
2478 | return REG_NOERROR; | ||
2479 | } | ||
2480 | |||
2481 | #if 0 | ||
2482 | /* Return the next state to which the current state STATE will transit by | ||
2483 | accepting the current input byte. */ | ||
2484 | |||
2485 | static re_dfastate_t * | ||
2486 | transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx, | ||
2487 | re_dfastate_t *state) | ||
2488 | { | ||
2489 | const re_dfa_t *const dfa = mctx->dfa; | ||
2490 | re_node_set next_nodes; | ||
2491 | re_dfastate_t *next_state; | ||
2492 | Idx node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input); | ||
2493 | unsigned int context; | ||
2494 | |||
2495 | *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1); | ||
2496 | if (BE (*err != REG_NOERROR, 0)) | ||
2497 | return NULL; | ||
2498 | for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt) | ||
2499 | { | ||
2500 | Idx cur_node = state->nodes.elems[node_cnt]; | ||
2501 | if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx)) | ||
2502 | { | ||
2503 | *err = re_node_set_merge (&next_nodes, | ||
2504 | dfa->eclosures + dfa->nexts[cur_node]); | ||
2505 | if (BE (*err != REG_NOERROR, 0)) | ||
2506 | { | ||
2507 | re_node_set_free (&next_nodes); | ||
2508 | return NULL; | ||
2509 | } | ||
2510 | } | ||
2511 | } | ||
2512 | context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags); | ||
2513 | next_state = re_acquire_state_context (err, dfa, &next_nodes, context); | ||
2514 | /* We don't need to check errors here, since the return value of | ||
2515 | this function is next_state and ERR is already set. */ | ||
2516 | |||
2517 | re_node_set_free (&next_nodes); | ||
2518 | re_string_skip_bytes (&mctx->input, 1); | ||
2519 | return next_state; | ||
2520 | } | ||
2521 | #endif | ||
2522 | |||
2523 | #ifdef RE_ENABLE_I18N | ||
2524 | static reg_errcode_t | ||
2525 | internal_function | ||
2526 | transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate) | ||
2527 | { | ||
2528 | const re_dfa_t *const dfa = mctx->dfa; | ||
2529 | reg_errcode_t err; | ||
2530 | Idx i; | ||
2531 | |||
2532 | for (i = 0; i < pstate->nodes.nelem; ++i) | ||
2533 | { | ||
2534 | re_node_set dest_nodes, *new_nodes; | ||
2535 | Idx cur_node_idx = pstate->nodes.elems[i]; | ||
2536 | int naccepted; | ||
2537 | Idx dest_idx; | ||
2538 | unsigned int context; | ||
2539 | re_dfastate_t *dest_state; | ||
2540 | |||
2541 | if (!dfa->nodes[cur_node_idx].accept_mb) | ||
2542 | continue; | ||
2543 | |||
2544 | if (dfa->nodes[cur_node_idx].constraint) | ||
2545 | { | ||
2546 | context = re_string_context_at (&mctx->input, | ||
2547 | re_string_cur_idx (&mctx->input), | ||
2548 | mctx->eflags); | ||
2549 | if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint, | ||
2550 | context)) | ||
2551 | continue; | ||
2552 | } | ||
2553 | |||
2554 | /* How many bytes the node can accept? */ | ||
2555 | naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input, | ||
2556 | re_string_cur_idx (&mctx->input)); | ||
2557 | if (naccepted == 0) | ||
2558 | continue; | ||
2559 | |||
2560 | /* The node can accepts `naccepted' bytes. */ | ||
2561 | dest_idx = re_string_cur_idx (&mctx->input) + naccepted; | ||
2562 | mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted | ||
2563 | : mctx->max_mb_elem_len); | ||
2564 | err = clean_state_log_if_needed (mctx, dest_idx); | ||
2565 | if (BE (err != REG_NOERROR, 0)) | ||
2566 | return err; | ||
2567 | #ifdef DEBUG | ||
2568 | assert (dfa->nexts[cur_node_idx] != REG_MISSING); | ||
2569 | #endif | ||
2570 | new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx]; | ||
2571 | |||
2572 | dest_state = mctx->state_log[dest_idx]; | ||
2573 | if (dest_state == NULL) | ||
2574 | dest_nodes = *new_nodes; | ||
2575 | else | ||
2576 | { | ||
2577 | err = re_node_set_init_union (&dest_nodes, | ||
2578 | dest_state->entrance_nodes, new_nodes); | ||
2579 | if (BE (err != REG_NOERROR, 0)) | ||
2580 | return err; | ||
2581 | } | ||
2582 | context = re_string_context_at (&mctx->input, dest_idx - 1, | ||
2583 | mctx->eflags); | ||
2584 | mctx->state_log[dest_idx] | ||
2585 | = re_acquire_state_context (&err, dfa, &dest_nodes, context); | ||
2586 | if (dest_state != NULL) | ||
2587 | re_node_set_free (&dest_nodes); | ||
2588 | if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0)) | ||
2589 | return err; | ||
2590 | } | ||
2591 | return REG_NOERROR; | ||
2592 | } | ||
2593 | #endif /* RE_ENABLE_I18N */ | ||
2594 | |||
2595 | static reg_errcode_t | ||
2596 | internal_function | ||
2597 | transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes) | ||
2598 | { | ||
2599 | const re_dfa_t *const dfa = mctx->dfa; | ||
2600 | reg_errcode_t err; | ||
2601 | Idx i; | ||
2602 | Idx cur_str_idx = re_string_cur_idx (&mctx->input); | ||
2603 | |||
2604 | for (i = 0; i < nodes->nelem; ++i) | ||
2605 | { | ||
2606 | Idx dest_str_idx, prev_nelem, bkc_idx; | ||
2607 | Idx node_idx = nodes->elems[i]; | ||
2608 | unsigned int context; | ||
2609 | const re_token_t *node = dfa->nodes + node_idx; | ||
2610 | re_node_set *new_dest_nodes; | ||
2611 | |||
2612 | /* Check whether `node' is a backreference or not. */ | ||
2613 | if (node->type != OP_BACK_REF) | ||
2614 | continue; | ||
2615 | |||
2616 | if (node->constraint) | ||
2617 | { | ||
2618 | context = re_string_context_at (&mctx->input, cur_str_idx, | ||
2619 | mctx->eflags); | ||
2620 | if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) | ||
2621 | continue; | ||
2622 | } | ||
2623 | |||
2624 | /* `node' is a backreference. | ||
2625 | Check the substring which the substring matched. */ | ||
2626 | bkc_idx = mctx->nbkref_ents; | ||
2627 | err = get_subexp (mctx, node_idx, cur_str_idx); | ||
2628 | if (BE (err != REG_NOERROR, 0)) | ||
2629 | goto free_return; | ||
2630 | |||
2631 | /* And add the epsilon closures (which is `new_dest_nodes') of | ||
2632 | the backreference to appropriate state_log. */ | ||
2633 | #ifdef DEBUG | ||
2634 | assert (dfa->nexts[node_idx] != REG_MISSING); | ||
2635 | #endif | ||
2636 | for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx) | ||
2637 | { | ||
2638 | Idx subexp_len; | ||
2639 | re_dfastate_t *dest_state; | ||
2640 | struct re_backref_cache_entry *bkref_ent; | ||
2641 | bkref_ent = mctx->bkref_ents + bkc_idx; | ||
2642 | if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx) | ||
2643 | continue; | ||
2644 | subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from; | ||
2645 | new_dest_nodes = (subexp_len == 0 | ||
2646 | ? dfa->eclosures + dfa->edests[node_idx].elems[0] | ||
2647 | : dfa->eclosures + dfa->nexts[node_idx]); | ||
2648 | dest_str_idx = (cur_str_idx + bkref_ent->subexp_to | ||
2649 | - bkref_ent->subexp_from); | ||
2650 | context = re_string_context_at (&mctx->input, dest_str_idx - 1, | ||
2651 | mctx->eflags); | ||
2652 | dest_state = mctx->state_log[dest_str_idx]; | ||
2653 | prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0 | ||
2654 | : mctx->state_log[cur_str_idx]->nodes.nelem); | ||
2655 | /* Add `new_dest_node' to state_log. */ | ||
2656 | if (dest_state == NULL) | ||
2657 | { | ||
2658 | mctx->state_log[dest_str_idx] | ||
2659 | = re_acquire_state_context (&err, dfa, new_dest_nodes, | ||
2660 | context); | ||
2661 | if (BE (mctx->state_log[dest_str_idx] == NULL | ||
2662 | && err != REG_NOERROR, 0)) | ||
2663 | goto free_return; | ||
2664 | } | ||
2665 | else | ||
2666 | { | ||
2667 | re_node_set dest_nodes; | ||
2668 | err = re_node_set_init_union (&dest_nodes, | ||
2669 | dest_state->entrance_nodes, | ||
2670 | new_dest_nodes); | ||
2671 | if (BE (err != REG_NOERROR, 0)) | ||
2672 | { | ||
2673 | re_node_set_free (&dest_nodes); | ||
2674 | goto free_return; | ||
2675 | } | ||
2676 | mctx->state_log[dest_str_idx] | ||
2677 | = re_acquire_state_context (&err, dfa, &dest_nodes, context); | ||
2678 | re_node_set_free (&dest_nodes); | ||
2679 | if (BE (mctx->state_log[dest_str_idx] == NULL | ||
2680 | && err != REG_NOERROR, 0)) | ||
2681 | goto free_return; | ||
2682 | } | ||
2683 | /* We need to check recursively if the backreference can epsilon | ||
2684 | transit. */ | ||
2685 | if (subexp_len == 0 | ||
2686 | && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem) | ||
2687 | { | ||
2688 | err = check_subexp_matching_top (mctx, new_dest_nodes, | ||
2689 | cur_str_idx); | ||
2690 | if (BE (err != REG_NOERROR, 0)) | ||
2691 | goto free_return; | ||
2692 | err = transit_state_bkref (mctx, new_dest_nodes); | ||
2693 | if (BE (err != REG_NOERROR, 0)) | ||
2694 | goto free_return; | ||
2695 | } | ||
2696 | } | ||
2697 | } | ||
2698 | err = REG_NOERROR; | ||
2699 | free_return: | ||
2700 | return err; | ||
2701 | } | ||
2702 | |||
2703 | /* Enumerate all the candidates which the backreference BKREF_NODE can match | ||
2704 | at BKREF_STR_IDX, and register them by match_ctx_add_entry(). | ||
2705 | Note that we might collect inappropriate candidates here. | ||
2706 | However, the cost of checking them strictly here is too high, then we | ||
2707 | delay these checking for prune_impossible_nodes(). */ | ||
2708 | |||
2709 | static reg_errcode_t | ||
2710 | internal_function | ||
2711 | get_subexp (re_match_context_t *mctx, Idx bkref_node, Idx bkref_str_idx) | ||
2712 | { | ||
2713 | const re_dfa_t *const dfa = mctx->dfa; | ||
2714 | Idx subexp_num, sub_top_idx; | ||
2715 | const char *buf = (const char *) re_string_get_buffer (&mctx->input); | ||
2716 | /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */ | ||
2717 | Idx cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx); | ||
2718 | if (cache_idx != REG_MISSING) | ||
2719 | { | ||
2720 | const struct re_backref_cache_entry *entry | ||
2721 | = mctx->bkref_ents + cache_idx; | ||
2722 | do | ||
2723 | if (entry->node == bkref_node) | ||
2724 | return REG_NOERROR; /* We already checked it. */ | ||
2725 | while (entry++->more); | ||
2726 | } | ||
2727 | |||
2728 | subexp_num = dfa->nodes[bkref_node].opr.idx; | ||
2729 | |||
2730 | /* For each sub expression */ | ||
2731 | for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx) | ||
2732 | { | ||
2733 | reg_errcode_t err; | ||
2734 | re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx]; | ||
2735 | re_sub_match_last_t *sub_last; | ||
2736 | Idx sub_last_idx, sl_str, bkref_str_off; | ||
2737 | |||
2738 | if (dfa->nodes[sub_top->node].opr.idx != subexp_num) | ||
2739 | continue; /* It isn't related. */ | ||
2740 | |||
2741 | sl_str = sub_top->str_idx; | ||
2742 | bkref_str_off = bkref_str_idx; | ||
2743 | /* At first, check the last node of sub expressions we already | ||
2744 | evaluated. */ | ||
2745 | for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx) | ||
2746 | { | ||
2747 | regoff_t sl_str_diff; | ||
2748 | sub_last = sub_top->lasts[sub_last_idx]; | ||
2749 | sl_str_diff = sub_last->str_idx - sl_str; | ||
2750 | /* The matched string by the sub expression match with the substring | ||
2751 | at the back reference? */ | ||
2752 | if (sl_str_diff > 0) | ||
2753 | { | ||
2754 | if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0)) | ||
2755 | { | ||
2756 | /* Not enough chars for a successful match. */ | ||
2757 | if (bkref_str_off + sl_str_diff > mctx->input.len) | ||
2758 | break; | ||
2759 | |||
2760 | err = clean_state_log_if_needed (mctx, | ||
2761 | bkref_str_off | ||
2762 | + sl_str_diff); | ||
2763 | if (BE (err != REG_NOERROR, 0)) | ||
2764 | return err; | ||
2765 | buf = (const char *) re_string_get_buffer (&mctx->input); | ||
2766 | } | ||
2767 | if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0) | ||
2768 | /* We don't need to search this sub expression any more. */ | ||
2769 | break; | ||
2770 | } | ||
2771 | bkref_str_off += sl_str_diff; | ||
2772 | sl_str += sl_str_diff; | ||
2773 | err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node, | ||
2774 | bkref_str_idx); | ||
2775 | |||
2776 | /* Reload buf, since the preceding call might have reallocated | ||
2777 | the buffer. */ | ||
2778 | buf = (const char *) re_string_get_buffer (&mctx->input); | ||
2779 | |||
2780 | if (err == REG_NOMATCH) | ||
2781 | continue; | ||
2782 | if (BE (err != REG_NOERROR, 0)) | ||
2783 | return err; | ||
2784 | } | ||
2785 | |||
2786 | if (sub_last_idx < sub_top->nlasts) | ||
2787 | continue; | ||
2788 | if (sub_last_idx > 0) | ||
2789 | ++sl_str; | ||
2790 | /* Then, search for the other last nodes of the sub expression. */ | ||
2791 | for (; sl_str <= bkref_str_idx; ++sl_str) | ||
2792 | { | ||
2793 | Idx cls_node; | ||
2794 | regoff_t sl_str_off; | ||
2795 | const re_node_set *nodes; | ||
2796 | sl_str_off = sl_str - sub_top->str_idx; | ||
2797 | /* The matched string by the sub expression match with the substring | ||
2798 | at the back reference? */ | ||
2799 | if (sl_str_off > 0) | ||
2800 | { | ||
2801 | if (BE (bkref_str_off >= mctx->input.valid_len, 0)) | ||
2802 | { | ||
2803 | /* If we are at the end of the input, we cannot match. */ | ||
2804 | if (bkref_str_off >= mctx->input.len) | ||
2805 | break; | ||
2806 | |||
2807 | err = extend_buffers (mctx); | ||
2808 | if (BE (err != REG_NOERROR, 0)) | ||
2809 | return err; | ||
2810 | |||
2811 | buf = (const char *) re_string_get_buffer (&mctx->input); | ||
2812 | } | ||
2813 | if (buf [bkref_str_off++] != buf[sl_str - 1]) | ||
2814 | break; /* We don't need to search this sub expression | ||
2815 | any more. */ | ||
2816 | } | ||
2817 | if (mctx->state_log[sl_str] == NULL) | ||
2818 | continue; | ||
2819 | /* Does this state have a ')' of the sub expression? */ | ||
2820 | nodes = &mctx->state_log[sl_str]->nodes; | ||
2821 | cls_node = find_subexp_node (dfa, nodes, subexp_num, | ||
2822 | OP_CLOSE_SUBEXP); | ||
2823 | if (cls_node == REG_MISSING) | ||
2824 | continue; /* No. */ | ||
2825 | if (sub_top->path == NULL) | ||
2826 | { | ||
2827 | sub_top->path = calloc (sizeof (state_array_t), | ||
2828 | sl_str - sub_top->str_idx + 1); | ||
2829 | if (sub_top->path == NULL) | ||
2830 | return REG_ESPACE; | ||
2831 | } | ||
2832 | /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node | ||
2833 | in the current context? */ | ||
2834 | err = check_arrival (mctx, sub_top->path, sub_top->node, | ||
2835 | sub_top->str_idx, cls_node, sl_str, | ||
2836 | OP_CLOSE_SUBEXP); | ||
2837 | if (err == REG_NOMATCH) | ||
2838 | continue; | ||
2839 | if (BE (err != REG_NOERROR, 0)) | ||
2840 | return err; | ||
2841 | sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str); | ||
2842 | if (BE (sub_last == NULL, 0)) | ||
2843 | return REG_ESPACE; | ||
2844 | err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node, | ||
2845 | bkref_str_idx); | ||
2846 | if (err == REG_NOMATCH) | ||
2847 | continue; | ||
2848 | } | ||
2849 | } | ||
2850 | return REG_NOERROR; | ||
2851 | } | ||
2852 | |||
2853 | /* Helper functions for get_subexp(). */ | ||
2854 | |||
2855 | /* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR. | ||
2856 | If it can arrive, register the sub expression expressed with SUB_TOP | ||
2857 | and SUB_LAST. */ | ||
2858 | |||
2859 | static reg_errcode_t | ||
2860 | internal_function | ||
2861 | get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top, | ||
2862 | re_sub_match_last_t *sub_last, Idx bkref_node, Idx bkref_str) | ||
2863 | { | ||
2864 | reg_errcode_t err; | ||
2865 | Idx to_idx; | ||
2866 | /* Can the subexpression arrive the back reference? */ | ||
2867 | err = check_arrival (mctx, &sub_last->path, sub_last->node, | ||
2868 | sub_last->str_idx, bkref_node, bkref_str, | ||
2869 | OP_OPEN_SUBEXP); | ||
2870 | if (err != REG_NOERROR) | ||
2871 | return err; | ||
2872 | err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx, | ||
2873 | sub_last->str_idx); | ||
2874 | if (BE (err != REG_NOERROR, 0)) | ||
2875 | return err; | ||
2876 | to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx; | ||
2877 | return clean_state_log_if_needed (mctx, to_idx); | ||
2878 | } | ||
2879 | |||
2880 | /* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX. | ||
2881 | Search '(' if FL_OPEN, or search ')' otherwise. | ||
2882 | TODO: This function isn't efficient... | ||
2883 | Because there might be more than one nodes whose types are | ||
2884 | OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all | ||
2885 | nodes. | ||
2886 | E.g. RE: (a){2} */ | ||
2887 | |||
2888 | static Idx | ||
2889 | internal_function | ||
2890 | find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, | ||
2891 | Idx subexp_idx, int type) | ||
2892 | { | ||
2893 | Idx cls_idx; | ||
2894 | for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx) | ||
2895 | { | ||
2896 | Idx cls_node = nodes->elems[cls_idx]; | ||
2897 | const re_token_t *node = dfa->nodes + cls_node; | ||
2898 | if (node->type == type | ||
2899 | && node->opr.idx == subexp_idx) | ||
2900 | return cls_node; | ||
2901 | } | ||
2902 | return REG_MISSING; | ||
2903 | } | ||
2904 | |||
2905 | /* Check whether the node TOP_NODE at TOP_STR can arrive to the node | ||
2906 | LAST_NODE at LAST_STR. We record the path onto PATH since it will be | ||
2907 | heavily reused. | ||
2908 | Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */ | ||
2909 | |||
2910 | static reg_errcode_t | ||
2911 | internal_function | ||
2912 | check_arrival (re_match_context_t *mctx, state_array_t *path, Idx top_node, | ||
2913 | Idx top_str, Idx last_node, Idx last_str, int type) | ||
2914 | { | ||
2915 | const re_dfa_t *const dfa = mctx->dfa; | ||
2916 | reg_errcode_t err = REG_NOERROR; | ||
2917 | Idx subexp_num, backup_cur_idx, str_idx, null_cnt; | ||
2918 | re_dfastate_t *cur_state = NULL; | ||
2919 | re_node_set *cur_nodes, next_nodes; | ||
2920 | re_dfastate_t **backup_state_log; | ||
2921 | unsigned int context; | ||
2922 | |||
2923 | subexp_num = dfa->nodes[top_node].opr.idx; | ||
2924 | /* Extend the buffer if we need. */ | ||
2925 | if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0)) | ||
2926 | { | ||
2927 | re_dfastate_t **new_array; | ||
2928 | Idx old_alloc = path->alloc; | ||
2929 | Idx new_alloc = old_alloc + last_str + mctx->max_mb_elem_len + 1; | ||
2930 | if (BE (new_alloc < old_alloc, 0) | ||
2931 | || BE (SIZE_MAX / sizeof (re_dfastate_t *) < new_alloc, 0)) | ||
2932 | return REG_ESPACE; | ||
2933 | new_array = re_realloc (path->array, re_dfastate_t *, new_alloc); | ||
2934 | if (BE (new_array == NULL, 0)) | ||
2935 | return REG_ESPACE; | ||
2936 | path->array = new_array; | ||
2937 | path->alloc = new_alloc; | ||
2938 | memset (new_array + old_alloc, '\0', | ||
2939 | sizeof (re_dfastate_t *) * (path->alloc - old_alloc)); | ||
2940 | } | ||
2941 | |||
2942 | str_idx = path->next_idx ? path->next_idx : top_str; | ||
2943 | |||
2944 | /* Temporary modify MCTX. */ | ||
2945 | backup_state_log = mctx->state_log; | ||
2946 | backup_cur_idx = mctx->input.cur_idx; | ||
2947 | mctx->state_log = path->array; | ||
2948 | mctx->input.cur_idx = str_idx; | ||
2949 | |||
2950 | /* Setup initial node set. */ | ||
2951 | context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags); | ||
2952 | if (str_idx == top_str) | ||
2953 | { | ||
2954 | err = re_node_set_init_1 (&next_nodes, top_node); | ||
2955 | if (BE (err != REG_NOERROR, 0)) | ||
2956 | return err; | ||
2957 | err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type); | ||
2958 | if (BE (err != REG_NOERROR, 0)) | ||
2959 | { | ||
2960 | re_node_set_free (&next_nodes); | ||
2961 | return err; | ||
2962 | } | ||
2963 | } | ||
2964 | else | ||
2965 | { | ||
2966 | cur_state = mctx->state_log[str_idx]; | ||
2967 | if (cur_state && cur_state->has_backref) | ||
2968 | { | ||
2969 | err = re_node_set_init_copy (&next_nodes, &cur_state->nodes); | ||
2970 | if (BE (err != REG_NOERROR, 0)) | ||
2971 | return err; | ||
2972 | } | ||
2973 | else | ||
2974 | re_node_set_init_empty (&next_nodes); | ||
2975 | } | ||
2976 | if (str_idx == top_str || (cur_state && cur_state->has_backref)) | ||
2977 | { | ||
2978 | if (next_nodes.nelem) | ||
2979 | { | ||
2980 | err = expand_bkref_cache (mctx, &next_nodes, str_idx, | ||
2981 | subexp_num, type); | ||
2982 | if (BE (err != REG_NOERROR, 0)) | ||
2983 | { | ||
2984 | re_node_set_free (&next_nodes); | ||
2985 | return err; | ||
2986 | } | ||
2987 | } | ||
2988 | cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); | ||
2989 | if (BE (cur_state == NULL && err != REG_NOERROR, 0)) | ||
2990 | { | ||
2991 | re_node_set_free (&next_nodes); | ||
2992 | return err; | ||
2993 | } | ||
2994 | mctx->state_log[str_idx] = cur_state; | ||
2995 | } | ||
2996 | |||
2997 | for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;) | ||
2998 | { | ||
2999 | re_node_set_empty (&next_nodes); | ||
3000 | if (mctx->state_log[str_idx + 1]) | ||
3001 | { | ||
3002 | err = re_node_set_merge (&next_nodes, | ||
3003 | &mctx->state_log[str_idx + 1]->nodes); | ||
3004 | if (BE (err != REG_NOERROR, 0)) | ||
3005 | { | ||
3006 | re_node_set_free (&next_nodes); | ||
3007 | return err; | ||
3008 | } | ||
3009 | } | ||
3010 | if (cur_state) | ||
3011 | { | ||
3012 | err = check_arrival_add_next_nodes (mctx, str_idx, | ||
3013 | &cur_state->non_eps_nodes, | ||
3014 | &next_nodes); | ||
3015 | if (BE (err != REG_NOERROR, 0)) | ||
3016 | { | ||
3017 | re_node_set_free (&next_nodes); | ||
3018 | return err; | ||
3019 | } | ||
3020 | } | ||
3021 | ++str_idx; | ||
3022 | if (next_nodes.nelem) | ||
3023 | { | ||
3024 | err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type); | ||
3025 | if (BE (err != REG_NOERROR, 0)) | ||
3026 | { | ||
3027 | re_node_set_free (&next_nodes); | ||
3028 | return err; | ||
3029 | } | ||
3030 | err = expand_bkref_cache (mctx, &next_nodes, str_idx, | ||
3031 | subexp_num, type); | ||
3032 | if (BE (err != REG_NOERROR, 0)) | ||
3033 | { | ||
3034 | re_node_set_free (&next_nodes); | ||
3035 | return err; | ||
3036 | } | ||
3037 | } | ||
3038 | context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags); | ||
3039 | cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); | ||
3040 | if (BE (cur_state == NULL && err != REG_NOERROR, 0)) | ||
3041 | { | ||
3042 | re_node_set_free (&next_nodes); | ||
3043 | return err; | ||
3044 | } | ||
3045 | mctx->state_log[str_idx] = cur_state; | ||
3046 | null_cnt = cur_state == NULL ? null_cnt + 1 : 0; | ||
3047 | } | ||
3048 | re_node_set_free (&next_nodes); | ||
3049 | cur_nodes = (mctx->state_log[last_str] == NULL ? NULL | ||
3050 | : &mctx->state_log[last_str]->nodes); | ||
3051 | path->next_idx = str_idx; | ||
3052 | |||
3053 | /* Fix MCTX. */ | ||
3054 | mctx->state_log = backup_state_log; | ||
3055 | mctx->input.cur_idx = backup_cur_idx; | ||
3056 | |||
3057 | /* Then check the current node set has the node LAST_NODE. */ | ||
3058 | if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node)) | ||
3059 | return REG_NOERROR; | ||
3060 | |||
3061 | return REG_NOMATCH; | ||
3062 | } | ||
3063 | |||
3064 | /* Helper functions for check_arrival. */ | ||
3065 | |||
3066 | /* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them | ||
3067 | to NEXT_NODES. | ||
3068 | TODO: This function is similar to the functions transit_state*(), | ||
3069 | however this function has many additional works. | ||
3070 | Can't we unify them? */ | ||
3071 | |||
3072 | static reg_errcode_t | ||
3073 | internal_function | ||
3074 | check_arrival_add_next_nodes (re_match_context_t *mctx, Idx str_idx, | ||
3075 | re_node_set *cur_nodes, re_node_set *next_nodes) | ||
3076 | { | ||
3077 | const re_dfa_t *const dfa = mctx->dfa; | ||
3078 | bool ok; | ||
3079 | Idx cur_idx; | ||
3080 | reg_errcode_t err = REG_NOERROR; | ||
3081 | re_node_set union_set; | ||
3082 | re_node_set_init_empty (&union_set); | ||
3083 | for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx) | ||
3084 | { | ||
3085 | int naccepted = 0; | ||
3086 | Idx cur_node = cur_nodes->elems[cur_idx]; | ||
3087 | #ifdef DEBUG | ||
3088 | re_token_type_t type = dfa->nodes[cur_node].type; | ||
3089 | assert (!IS_EPSILON_NODE (type)); | ||
3090 | #endif | ||
3091 | #ifdef RE_ENABLE_I18N | ||
3092 | /* If the node may accept `multi byte'. */ | ||
3093 | if (dfa->nodes[cur_node].accept_mb) | ||
3094 | { | ||
3095 | naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input, | ||
3096 | str_idx); | ||
3097 | if (naccepted > 1) | ||
3098 | { | ||
3099 | re_dfastate_t *dest_state; | ||
3100 | Idx next_node = dfa->nexts[cur_node]; | ||
3101 | Idx next_idx = str_idx + naccepted; | ||
3102 | dest_state = mctx->state_log[next_idx]; | ||
3103 | re_node_set_empty (&union_set); | ||
3104 | if (dest_state) | ||
3105 | { | ||
3106 | err = re_node_set_merge (&union_set, &dest_state->nodes); | ||
3107 | if (BE (err != REG_NOERROR, 0)) | ||
3108 | { | ||
3109 | re_node_set_free (&union_set); | ||
3110 | return err; | ||
3111 | } | ||
3112 | } | ||
3113 | ok = re_node_set_insert (&union_set, next_node); | ||
3114 | if (BE (! ok, 0)) | ||
3115 | { | ||
3116 | re_node_set_free (&union_set); | ||
3117 | return REG_ESPACE; | ||
3118 | } | ||
3119 | mctx->state_log[next_idx] = re_acquire_state (&err, dfa, | ||
3120 | &union_set); | ||
3121 | if (BE (mctx->state_log[next_idx] == NULL | ||
3122 | && err != REG_NOERROR, 0)) | ||
3123 | { | ||
3124 | re_node_set_free (&union_set); | ||
3125 | return err; | ||
3126 | } | ||
3127 | } | ||
3128 | } | ||
3129 | #endif /* RE_ENABLE_I18N */ | ||
3130 | if (naccepted | ||
3131 | || check_node_accept (mctx, dfa->nodes + cur_node, str_idx)) | ||
3132 | { | ||
3133 | ok = re_node_set_insert (next_nodes, dfa->nexts[cur_node]); | ||
3134 | if (BE (! ok, 0)) | ||
3135 | { | ||
3136 | re_node_set_free (&union_set); | ||
3137 | return REG_ESPACE; | ||
3138 | } | ||
3139 | } | ||
3140 | } | ||
3141 | re_node_set_free (&union_set); | ||
3142 | return REG_NOERROR; | ||
3143 | } | ||
3144 | |||
3145 | /* For all the nodes in CUR_NODES, add the epsilon closures of them to | ||
3146 | CUR_NODES, however exclude the nodes which are: | ||
3147 | - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN. | ||
3148 | - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN. | ||
3149 | */ | ||
3150 | |||
3151 | static reg_errcode_t | ||
3152 | internal_function | ||
3153 | check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes, | ||
3154 | Idx ex_subexp, int type) | ||
3155 | { | ||
3156 | reg_errcode_t err; | ||
3157 | Idx idx, outside_node; | ||
3158 | re_node_set new_nodes; | ||
3159 | #ifdef DEBUG | ||
3160 | assert (cur_nodes->nelem); | ||
3161 | #endif | ||
3162 | err = re_node_set_alloc (&new_nodes, cur_nodes->nelem); | ||
3163 | if (BE (err != REG_NOERROR, 0)) | ||
3164 | return err; | ||
3165 | /* Create a new node set NEW_NODES with the nodes which are epsilon | ||
3166 | closures of the node in CUR_NODES. */ | ||
3167 | |||
3168 | for (idx = 0; idx < cur_nodes->nelem; ++idx) | ||
3169 | { | ||
3170 | Idx cur_node = cur_nodes->elems[idx]; | ||
3171 | const re_node_set *eclosure = dfa->eclosures + cur_node; | ||
3172 | outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type); | ||
3173 | if (outside_node == REG_MISSING) | ||
3174 | { | ||
3175 | /* There are no problematic nodes, just merge them. */ | ||
3176 | err = re_node_set_merge (&new_nodes, eclosure); | ||
3177 | if (BE (err != REG_NOERROR, 0)) | ||
3178 | { | ||
3179 | re_node_set_free (&new_nodes); | ||
3180 | return err; | ||
3181 | } | ||
3182 | } | ||
3183 | else | ||
3184 | { | ||
3185 | /* There are problematic nodes, re-calculate incrementally. */ | ||
3186 | err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node, | ||
3187 | ex_subexp, type); | ||
3188 | if (BE (err != REG_NOERROR, 0)) | ||
3189 | { | ||
3190 | re_node_set_free (&new_nodes); | ||
3191 | return err; | ||
3192 | } | ||
3193 | } | ||
3194 | } | ||
3195 | re_node_set_free (cur_nodes); | ||
3196 | *cur_nodes = new_nodes; | ||
3197 | return REG_NOERROR; | ||
3198 | } | ||
3199 | |||
3200 | /* Helper function for check_arrival_expand_ecl. | ||
3201 | Check incrementally the epsilon closure of TARGET, and if it isn't | ||
3202 | problematic append it to DST_NODES. */ | ||
3203 | |||
3204 | static reg_errcode_t | ||
3205 | internal_function | ||
3206 | check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes, | ||
3207 | Idx target, Idx ex_subexp, int type) | ||
3208 | { | ||
3209 | Idx cur_node; | ||
3210 | for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);) | ||
3211 | { | ||
3212 | bool ok; | ||
3213 | |||
3214 | if (dfa->nodes[cur_node].type == type | ||
3215 | && dfa->nodes[cur_node].opr.idx == ex_subexp) | ||
3216 | { | ||
3217 | if (type == OP_CLOSE_SUBEXP) | ||
3218 | { | ||
3219 | ok = re_node_set_insert (dst_nodes, cur_node); | ||
3220 | if (BE (! ok, 0)) | ||
3221 | return REG_ESPACE; | ||
3222 | } | ||
3223 | break; | ||
3224 | } | ||
3225 | ok = re_node_set_insert (dst_nodes, cur_node); | ||
3226 | if (BE (! ok, 0)) | ||
3227 | return REG_ESPACE; | ||
3228 | if (dfa->edests[cur_node].nelem == 0) | ||
3229 | break; | ||
3230 | if (dfa->edests[cur_node].nelem == 2) | ||
3231 | { | ||
3232 | reg_errcode_t err; | ||
3233 | err = check_arrival_expand_ecl_sub (dfa, dst_nodes, | ||
3234 | dfa->edests[cur_node].elems[1], | ||
3235 | ex_subexp, type); | ||
3236 | if (BE (err != REG_NOERROR, 0)) | ||
3237 | return err; | ||
3238 | } | ||
3239 | cur_node = dfa->edests[cur_node].elems[0]; | ||
3240 | } | ||
3241 | return REG_NOERROR; | ||
3242 | } | ||
3243 | |||
3244 | |||
3245 | /* For all the back references in the current state, calculate the | ||
3246 | destination of the back references by the appropriate entry | ||
3247 | in MCTX->BKREF_ENTS. */ | ||
3248 | |||
3249 | static reg_errcode_t | ||
3250 | internal_function | ||
3251 | expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes, | ||
3252 | Idx cur_str, Idx subexp_num, int type) | ||
3253 | { | ||
3254 | const re_dfa_t *const dfa = mctx->dfa; | ||
3255 | reg_errcode_t err; | ||
3256 | Idx cache_idx_start = search_cur_bkref_entry (mctx, cur_str); | ||
3257 | struct re_backref_cache_entry *ent; | ||
3258 | |||
3259 | if (cache_idx_start == REG_MISSING) | ||
3260 | return REG_NOERROR; | ||
3261 | |||
3262 | restart: | ||
3263 | ent = mctx->bkref_ents + cache_idx_start; | ||
3264 | do | ||
3265 | { | ||
3266 | Idx to_idx, next_node; | ||
3267 | |||
3268 | /* Is this entry ENT is appropriate? */ | ||
3269 | if (!re_node_set_contains (cur_nodes, ent->node)) | ||
3270 | continue; /* No. */ | ||
3271 | |||
3272 | to_idx = cur_str + ent->subexp_to - ent->subexp_from; | ||
3273 | /* Calculate the destination of the back reference, and append it | ||
3274 | to MCTX->STATE_LOG. */ | ||
3275 | if (to_idx == cur_str) | ||
3276 | { | ||
3277 | /* The backreference did epsilon transit, we must re-check all the | ||
3278 | node in the current state. */ | ||
3279 | re_node_set new_dests; | ||
3280 | reg_errcode_t err2, err3; | ||
3281 | next_node = dfa->edests[ent->node].elems[0]; | ||
3282 | if (re_node_set_contains (cur_nodes, next_node)) | ||
3283 | continue; | ||
3284 | err = re_node_set_init_1 (&new_dests, next_node); | ||
3285 | err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type); | ||
3286 | err3 = re_node_set_merge (cur_nodes, &new_dests); | ||
3287 | re_node_set_free (&new_dests); | ||
3288 | if (BE (err != REG_NOERROR || err2 != REG_NOERROR | ||
3289 | || err3 != REG_NOERROR, 0)) | ||
3290 | { | ||
3291 | err = (err != REG_NOERROR ? err | ||
3292 | : (err2 != REG_NOERROR ? err2 : err3)); | ||
3293 | return err; | ||
3294 | } | ||
3295 | /* TODO: It is still inefficient... */ | ||
3296 | goto restart; | ||
3297 | } | ||
3298 | else | ||
3299 | { | ||
3300 | re_node_set union_set; | ||
3301 | next_node = dfa->nexts[ent->node]; | ||
3302 | if (mctx->state_log[to_idx]) | ||
3303 | { | ||
3304 | bool ok; | ||
3305 | if (re_node_set_contains (&mctx->state_log[to_idx]->nodes, | ||
3306 | next_node)) | ||
3307 | continue; | ||
3308 | err = re_node_set_init_copy (&union_set, | ||
3309 | &mctx->state_log[to_idx]->nodes); | ||
3310 | ok = re_node_set_insert (&union_set, next_node); | ||
3311 | if (BE (err != REG_NOERROR || ! ok, 0)) | ||
3312 | { | ||
3313 | re_node_set_free (&union_set); | ||
3314 | err = err != REG_NOERROR ? err : REG_ESPACE; | ||
3315 | return err; | ||
3316 | } | ||
3317 | } | ||
3318 | else | ||
3319 | { | ||
3320 | err = re_node_set_init_1 (&union_set, next_node); | ||
3321 | if (BE (err != REG_NOERROR, 0)) | ||
3322 | return err; | ||
3323 | } | ||
3324 | mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set); | ||
3325 | re_node_set_free (&union_set); | ||
3326 | if (BE (mctx->state_log[to_idx] == NULL | ||
3327 | && err != REG_NOERROR, 0)) | ||
3328 | return err; | ||
3329 | } | ||
3330 | } | ||
3331 | while (ent++->more); | ||
3332 | return REG_NOERROR; | ||
3333 | } | ||
3334 | |||
3335 | /* Build transition table for the state. | ||
3336 | Return true if successful. */ | ||
3337 | |||
3338 | static bool | ||
3339 | internal_function | ||
3340 | build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) | ||
3341 | { | ||
3342 | reg_errcode_t err; | ||
3343 | Idx i, j; | ||
3344 | int ch; | ||
3345 | bool need_word_trtable = false; | ||
3346 | bitset_word_t elem, mask; | ||
3347 | bool dests_node_malloced = false; | ||
3348 | bool dest_states_malloced = false; | ||
3349 | Idx ndests; /* Number of the destination states from `state'. */ | ||
3350 | re_dfastate_t **trtable; | ||
3351 | re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl; | ||
3352 | re_node_set follows, *dests_node; | ||
3353 | bitset_t *dests_ch; | ||
3354 | bitset_t acceptable; | ||
3355 | |||
3356 | struct dests_alloc | ||
3357 | { | ||
3358 | re_node_set dests_node[SBC_MAX]; | ||
3359 | bitset_t dests_ch[SBC_MAX]; | ||
3360 | } *dests_alloc; | ||
3361 | |||
3362 | /* We build DFA states which corresponds to the destination nodes | ||
3363 | from `state'. `dests_node[i]' represents the nodes which i-th | ||
3364 | destination state contains, and `dests_ch[i]' represents the | ||
3365 | characters which i-th destination state accepts. */ | ||
3366 | if (__libc_use_alloca (sizeof (struct dests_alloc))) | ||
3367 | dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc)); | ||
3368 | else | ||
3369 | { | ||
3370 | dests_alloc = re_malloc (struct dests_alloc, 1); | ||
3371 | if (BE (dests_alloc == NULL, 0)) | ||
3372 | return false; | ||
3373 | dests_node_malloced = true; | ||
3374 | } | ||
3375 | dests_node = dests_alloc->dests_node; | ||
3376 | dests_ch = dests_alloc->dests_ch; | ||
3377 | |||
3378 | /* Initialize transiton table. */ | ||
3379 | state->word_trtable = state->trtable = NULL; | ||
3380 | |||
3381 | /* At first, group all nodes belonging to `state' into several | ||
3382 | destinations. */ | ||
3383 | ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch); | ||
3384 | if (BE (! REG_VALID_NONZERO_INDEX (ndests), 0)) | ||
3385 | { | ||
3386 | if (dests_node_malloced) | ||
3387 | free (dests_alloc); | ||
3388 | if (ndests == 0) | ||
3389 | { | ||
3390 | state->trtable = (re_dfastate_t **) | ||
3391 | calloc (sizeof (re_dfastate_t *), SBC_MAX); | ||
3392 | return true; | ||
3393 | } | ||
3394 | return false; | ||
3395 | } | ||
3396 | |||
3397 | err = re_node_set_alloc (&follows, ndests + 1); | ||
3398 | if (BE (err != REG_NOERROR, 0)) | ||
3399 | goto out_free; | ||
3400 | |||
3401 | /* Avoid arithmetic overflow in size calculation. */ | ||
3402 | if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX) | ||
3403 | / (3 * sizeof (re_dfastate_t *))) | ||
3404 | < ndests), | ||
3405 | 0)) | ||
3406 | goto out_free; | ||
3407 | |||
3408 | if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX | ||
3409 | + ndests * 3 * sizeof (re_dfastate_t *))) | ||
3410 | dest_states = (re_dfastate_t **) | ||
3411 | alloca (ndests * 3 * sizeof (re_dfastate_t *)); | ||
3412 | else | ||
3413 | { | ||
3414 | dest_states = (re_dfastate_t **) | ||
3415 | malloc (ndests * 3 * sizeof (re_dfastate_t *)); | ||
3416 | if (BE (dest_states == NULL, 0)) | ||
3417 | { | ||
3418 | out_free: | ||
3419 | if (dest_states_malloced) | ||
3420 | free (dest_states); | ||
3421 | re_node_set_free (&follows); | ||
3422 | for (i = 0; i < ndests; ++i) | ||
3423 | re_node_set_free (dests_node + i); | ||
3424 | if (dests_node_malloced) | ||
3425 | free (dests_alloc); | ||
3426 | return false; | ||
3427 | } | ||
3428 | dest_states_malloced = true; | ||
3429 | } | ||
3430 | dest_states_word = dest_states + ndests; | ||
3431 | dest_states_nl = dest_states_word + ndests; | ||
3432 | bitset_empty (acceptable); | ||
3433 | |||
3434 | /* Then build the states for all destinations. */ | ||
3435 | for (i = 0; i < ndests; ++i) | ||
3436 | { | ||
3437 | Idx next_node; | ||
3438 | re_node_set_empty (&follows); | ||
3439 | /* Merge the follows of this destination states. */ | ||
3440 | for (j = 0; j < dests_node[i].nelem; ++j) | ||
3441 | { | ||
3442 | next_node = dfa->nexts[dests_node[i].elems[j]]; | ||
3443 | if (next_node != REG_MISSING) | ||
3444 | { | ||
3445 | err = re_node_set_merge (&follows, dfa->eclosures + next_node); | ||
3446 | if (BE (err != REG_NOERROR, 0)) | ||
3447 | goto out_free; | ||
3448 | } | ||
3449 | } | ||
3450 | dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0); | ||
3451 | if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0)) | ||
3452 | goto out_free; | ||
3453 | /* If the new state has context constraint, | ||
3454 | build appropriate states for these contexts. */ | ||
3455 | if (dest_states[i]->has_constraint) | ||
3456 | { | ||
3457 | dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows, | ||
3458 | CONTEXT_WORD); | ||
3459 | if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0)) | ||
3460 | goto out_free; | ||
3461 | |||
3462 | if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1) | ||
3463 | need_word_trtable = true; | ||
3464 | |||
3465 | dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, | ||
3466 | CONTEXT_NEWLINE); | ||
3467 | if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0)) | ||
3468 | goto out_free; | ||
3469 | } | ||
3470 | else | ||
3471 | { | ||
3472 | dest_states_word[i] = dest_states[i]; | ||
3473 | dest_states_nl[i] = dest_states[i]; | ||
3474 | } | ||
3475 | bitset_merge (acceptable, dests_ch[i]); | ||
3476 | } | ||
3477 | |||
3478 | if (!BE (need_word_trtable, 0)) | ||
3479 | { | ||
3480 | /* We don't care about whether the following character is a word | ||
3481 | character, or we are in a single-byte character set so we can | ||
3482 | discern by looking at the character code: allocate a | ||
3483 | 256-entry transition table. */ | ||
3484 | trtable = state->trtable = | ||
3485 | (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); | ||
3486 | if (BE (trtable == NULL, 0)) | ||
3487 | goto out_free; | ||
3488 | |||
3489 | /* For all characters ch...: */ | ||
3490 | for (i = 0; i < BITSET_WORDS; ++i) | ||
3491 | for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; | ||
3492 | elem; | ||
3493 | mask <<= 1, elem >>= 1, ++ch) | ||
3494 | if (BE (elem & 1, 0)) | ||
3495 | { | ||
3496 | /* There must be exactly one destination which accepts | ||
3497 | character ch. See group_nodes_into_DFAstates. */ | ||
3498 | for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) | ||
3499 | ; | ||
3500 | |||
3501 | /* j-th destination accepts the word character ch. */ | ||
3502 | if (dfa->word_char[i] & mask) | ||
3503 | trtable[ch] = dest_states_word[j]; | ||
3504 | else | ||
3505 | trtable[ch] = dest_states[j]; | ||
3506 | } | ||
3507 | } | ||
3508 | else | ||
3509 | { | ||
3510 | /* We care about whether the following character is a word | ||
3511 | character, and we are in a multi-byte character set: discern | ||
3512 | by looking at the character code: build two 256-entry | ||
3513 | transition tables, one starting at trtable[0] and one | ||
3514 | starting at trtable[SBC_MAX]. */ | ||
3515 | trtable = state->word_trtable = | ||
3516 | (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); | ||
3517 | if (BE (trtable == NULL, 0)) | ||
3518 | goto out_free; | ||
3519 | |||
3520 | /* For all characters ch...: */ | ||
3521 | for (i = 0; i < BITSET_WORDS; ++i) | ||
3522 | for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; | ||
3523 | elem; | ||
3524 | mask <<= 1, elem >>= 1, ++ch) | ||
3525 | if (BE (elem & 1, 0)) | ||
3526 | { | ||
3527 | /* There must be exactly one destination which accepts | ||
3528 | character ch. See group_nodes_into_DFAstates. */ | ||
3529 | for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) | ||
3530 | ; | ||
3531 | |||
3532 | /* j-th destination accepts the word character ch. */ | ||
3533 | trtable[ch] = dest_states[j]; | ||
3534 | trtable[ch + SBC_MAX] = dest_states_word[j]; | ||
3535 | } | ||
3536 | } | ||
3537 | |||
3538 | /* new line */ | ||
3539 | if (bitset_contain (acceptable, NEWLINE_CHAR)) | ||
3540 | { | ||
3541 | /* The current state accepts newline character. */ | ||
3542 | for (j = 0; j < ndests; ++j) | ||
3543 | if (bitset_contain (dests_ch[j], NEWLINE_CHAR)) | ||
3544 | { | ||
3545 | /* k-th destination accepts newline character. */ | ||
3546 | trtable[NEWLINE_CHAR] = dest_states_nl[j]; | ||
3547 | if (need_word_trtable) | ||
3548 | trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j]; | ||
3549 | /* There must be only one destination which accepts | ||
3550 | newline. See group_nodes_into_DFAstates. */ | ||
3551 | break; | ||
3552 | } | ||
3553 | } | ||
3554 | |||
3555 | if (dest_states_malloced) | ||
3556 | free (dest_states); | ||
3557 | |||
3558 | re_node_set_free (&follows); | ||
3559 | for (i = 0; i < ndests; ++i) | ||
3560 | re_node_set_free (dests_node + i); | ||
3561 | |||
3562 | if (dests_node_malloced) | ||
3563 | free (dests_alloc); | ||
3564 | |||
3565 | return true; | ||
3566 | } | ||
3567 | |||
3568 | /* Group all nodes belonging to STATE into several destinations. | ||
3569 | Then for all destinations, set the nodes belonging to the destination | ||
3570 | to DESTS_NODE[i] and set the characters accepted by the destination | ||
3571 | to DEST_CH[i]. This function return the number of destinations. */ | ||
3572 | |||
3573 | static Idx | ||
3574 | internal_function | ||
3575 | group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, | ||
3576 | re_node_set *dests_node, bitset_t *dests_ch) | ||
3577 | { | ||
3578 | reg_errcode_t err; | ||
3579 | bool ok; | ||
3580 | Idx i, j, k; | ||
3581 | Idx ndests; /* Number of the destinations from `state'. */ | ||
3582 | bitset_t accepts; /* Characters a node can accept. */ | ||
3583 | const re_node_set *cur_nodes = &state->nodes; | ||
3584 | bitset_empty (accepts); | ||
3585 | ndests = 0; | ||
3586 | |||
3587 | /* For all the nodes belonging to `state', */ | ||
3588 | for (i = 0; i < cur_nodes->nelem; ++i) | ||
3589 | { | ||
3590 | re_token_t *node = &dfa->nodes[cur_nodes->elems[i]]; | ||
3591 | re_token_type_t type = node->type; | ||
3592 | unsigned int constraint = node->constraint; | ||
3593 | |||
3594 | /* Enumerate all single byte character this node can accept. */ | ||
3595 | if (type == CHARACTER) | ||
3596 | bitset_set (accepts, node->opr.c); | ||
3597 | else if (type == SIMPLE_BRACKET) | ||
3598 | { | ||
3599 | bitset_merge (accepts, node->opr.sbcset); | ||
3600 | } | ||
3601 | else if (type == OP_PERIOD) | ||
3602 | { | ||
3603 | #ifdef RE_ENABLE_I18N | ||
3604 | if (dfa->mb_cur_max > 1) | ||
3605 | bitset_merge (accepts, dfa->sb_char); | ||
3606 | else | ||
3607 | #endif | ||
3608 | bitset_set_all (accepts); | ||
3609 | if (!(dfa->syntax & RE_DOT_NEWLINE)) | ||
3610 | bitset_clear (accepts, '\n'); | ||
3611 | if (dfa->syntax & RE_DOT_NOT_NULL) | ||
3612 | bitset_clear (accepts, '\0'); | ||
3613 | } | ||
3614 | #ifdef RE_ENABLE_I18N | ||
3615 | else if (type == OP_UTF8_PERIOD) | ||
3616 | { | ||
3617 | if (ASCII_CHARS % BITSET_WORD_BITS == 0) | ||
3618 | memset (accepts, -1, ASCII_CHARS / CHAR_BIT); | ||
3619 | else | ||
3620 | bitset_merge (accepts, utf8_sb_map); | ||
3621 | if (!(dfa->syntax & RE_DOT_NEWLINE)) | ||
3622 | bitset_clear (accepts, '\n'); | ||
3623 | if (dfa->syntax & RE_DOT_NOT_NULL) | ||
3624 | bitset_clear (accepts, '\0'); | ||
3625 | } | ||
3626 | #endif | ||
3627 | else | ||
3628 | continue; | ||
3629 | |||
3630 | /* Check the `accepts' and sift the characters which are not | ||
3631 | match it the context. */ | ||
3632 | if (constraint) | ||
3633 | { | ||
3634 | if (constraint & NEXT_NEWLINE_CONSTRAINT) | ||
3635 | { | ||
3636 | bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); | ||
3637 | bitset_empty (accepts); | ||
3638 | if (accepts_newline) | ||
3639 | bitset_set (accepts, NEWLINE_CHAR); | ||
3640 | else | ||
3641 | continue; | ||
3642 | } | ||
3643 | if (constraint & NEXT_ENDBUF_CONSTRAINT) | ||
3644 | { | ||
3645 | bitset_empty (accepts); | ||
3646 | continue; | ||
3647 | } | ||
3648 | |||
3649 | if (constraint & NEXT_WORD_CONSTRAINT) | ||
3650 | { | ||
3651 | bitset_word_t any_set = 0; | ||
3652 | if (type == CHARACTER && !node->word_char) | ||
3653 | { | ||
3654 | bitset_empty (accepts); | ||
3655 | continue; | ||
3656 | } | ||
3657 | #ifdef RE_ENABLE_I18N | ||
3658 | if (dfa->mb_cur_max > 1) | ||
3659 | for (j = 0; j < BITSET_WORDS; ++j) | ||
3660 | any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j])); | ||
3661 | else | ||
3662 | #endif | ||
3663 | for (j = 0; j < BITSET_WORDS; ++j) | ||
3664 | any_set |= (accepts[j] &= dfa->word_char[j]); | ||
3665 | if (!any_set) | ||
3666 | continue; | ||
3667 | } | ||
3668 | if (constraint & NEXT_NOTWORD_CONSTRAINT) | ||
3669 | { | ||
3670 | bitset_word_t any_set = 0; | ||
3671 | if (type == CHARACTER && node->word_char) | ||
3672 | { | ||
3673 | bitset_empty (accepts); | ||
3674 | continue; | ||
3675 | } | ||
3676 | #ifdef RE_ENABLE_I18N | ||
3677 | if (dfa->mb_cur_max > 1) | ||
3678 | for (j = 0; j < BITSET_WORDS; ++j) | ||
3679 | any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j])); | ||
3680 | else | ||
3681 | #endif | ||
3682 | for (j = 0; j < BITSET_WORDS; ++j) | ||
3683 | any_set |= (accepts[j] &= ~dfa->word_char[j]); | ||
3684 | if (!any_set) | ||
3685 | continue; | ||
3686 | } | ||
3687 | } | ||
3688 | |||
3689 | /* Then divide `accepts' into DFA states, or create a new | ||
3690 | state. Above, we make sure that accepts is not empty. */ | ||
3691 | for (j = 0; j < ndests; ++j) | ||
3692 | { | ||
3693 | bitset_t intersec; /* Intersection sets, see below. */ | ||
3694 | bitset_t remains; | ||
3695 | /* Flags, see below. */ | ||
3696 | bitset_word_t has_intersec, not_subset, not_consumed; | ||
3697 | |||
3698 | /* Optimization, skip if this state doesn't accept the character. */ | ||
3699 | if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c)) | ||
3700 | continue; | ||
3701 | |||
3702 | /* Enumerate the intersection set of this state and `accepts'. */ | ||
3703 | has_intersec = 0; | ||
3704 | for (k = 0; k < BITSET_WORDS; ++k) | ||
3705 | has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k]; | ||
3706 | /* And skip if the intersection set is empty. */ | ||
3707 | if (!has_intersec) | ||
3708 | continue; | ||
3709 | |||
3710 | /* Then check if this state is a subset of `accepts'. */ | ||
3711 | not_subset = not_consumed = 0; | ||
3712 | for (k = 0; k < BITSET_WORDS; ++k) | ||
3713 | { | ||
3714 | not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k]; | ||
3715 | not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k]; | ||
3716 | } | ||
3717 | |||
3718 | /* If this state isn't a subset of `accepts', create a | ||
3719 | new group state, which has the `remains'. */ | ||
3720 | if (not_subset) | ||
3721 | { | ||
3722 | bitset_copy (dests_ch[ndests], remains); | ||
3723 | bitset_copy (dests_ch[j], intersec); | ||
3724 | err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]); | ||
3725 | if (BE (err != REG_NOERROR, 0)) | ||
3726 | goto error_return; | ||
3727 | ++ndests; | ||
3728 | } | ||
3729 | |||
3730 | /* Put the position in the current group. */ | ||
3731 | ok = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]); | ||
3732 | if (BE (! ok, 0)) | ||
3733 | goto error_return; | ||
3734 | |||
3735 | /* If all characters are consumed, go to next node. */ | ||
3736 | if (!not_consumed) | ||
3737 | break; | ||
3738 | } | ||
3739 | /* Some characters remain, create a new group. */ | ||
3740 | if (j == ndests) | ||
3741 | { | ||
3742 | bitset_copy (dests_ch[ndests], accepts); | ||
3743 | err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]); | ||
3744 | if (BE (err != REG_NOERROR, 0)) | ||
3745 | goto error_return; | ||
3746 | ++ndests; | ||
3747 | bitset_empty (accepts); | ||
3748 | } | ||
3749 | } | ||
3750 | return ndests; | ||
3751 | error_return: | ||
3752 | for (j = 0; j < ndests; ++j) | ||
3753 | re_node_set_free (dests_node + j); | ||
3754 | return REG_MISSING; | ||
3755 | } | ||
3756 | |||
3757 | #ifdef RE_ENABLE_I18N | ||
3758 | /* Check how many bytes the node `dfa->nodes[node_idx]' accepts. | ||
3759 | Return the number of the bytes the node accepts. | ||
3760 | STR_IDX is the current index of the input string. | ||
3761 | |||
3762 | This function handles the nodes which can accept one character, or | ||
3763 | one collating element like '.', '[a-z]', opposite to the other nodes | ||
3764 | can only accept one byte. */ | ||
3765 | |||
3766 | static int | ||
3767 | internal_function | ||
3768 | check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx, | ||
3769 | const re_string_t *input, Idx str_idx) | ||
3770 | { | ||
3771 | const re_token_t *node = dfa->nodes + node_idx; | ||
3772 | int char_len, elem_len; | ||
3773 | Idx i; | ||
3774 | |||
3775 | if (BE (node->type == OP_UTF8_PERIOD, 0)) | ||
3776 | { | ||
3777 | unsigned char c = re_string_byte_at (input, str_idx), d; | ||
3778 | if (BE (c < 0xc2, 1)) | ||
3779 | return 0; | ||
3780 | |||
3781 | if (str_idx + 2 > input->len) | ||
3782 | return 0; | ||
3783 | |||
3784 | d = re_string_byte_at (input, str_idx + 1); | ||
3785 | if (c < 0xe0) | ||
3786 | return (d < 0x80 || d > 0xbf) ? 0 : 2; | ||
3787 | else if (c < 0xf0) | ||
3788 | { | ||
3789 | char_len = 3; | ||
3790 | if (c == 0xe0 && d < 0xa0) | ||
3791 | return 0; | ||
3792 | } | ||
3793 | else if (c < 0xf8) | ||
3794 | { | ||
3795 | char_len = 4; | ||
3796 | if (c == 0xf0 && d < 0x90) | ||
3797 | return 0; | ||
3798 | } | ||
3799 | else if (c < 0xfc) | ||
3800 | { | ||
3801 | char_len = 5; | ||
3802 | if (c == 0xf8 && d < 0x88) | ||
3803 | return 0; | ||
3804 | } | ||
3805 | else if (c < 0xfe) | ||
3806 | { | ||
3807 | char_len = 6; | ||
3808 | if (c == 0xfc && d < 0x84) | ||
3809 | return 0; | ||
3810 | } | ||
3811 | else | ||
3812 | return 0; | ||
3813 | |||
3814 | if (str_idx + char_len > input->len) | ||
3815 | return 0; | ||
3816 | |||
3817 | for (i = 1; i < char_len; ++i) | ||
3818 | { | ||
3819 | d = re_string_byte_at (input, str_idx + i); | ||
3820 | if (d < 0x80 || d > 0xbf) | ||
3821 | return 0; | ||
3822 | } | ||
3823 | return char_len; | ||
3824 | } | ||
3825 | |||
3826 | char_len = re_string_char_size_at (input, str_idx); | ||
3827 | if (node->type == OP_PERIOD) | ||
3828 | { | ||
3829 | if (char_len <= 1) | ||
3830 | return 0; | ||
3831 | /* FIXME: I don't think this if is needed, as both '\n' | ||
3832 | and '\0' are char_len == 1. */ | ||
3833 | /* '.' accepts any one character except the following two cases. */ | ||
3834 | if ((!(dfa->syntax & RE_DOT_NEWLINE) && | ||
3835 | re_string_byte_at (input, str_idx) == '\n') || | ||
3836 | ((dfa->syntax & RE_DOT_NOT_NULL) && | ||
3837 | re_string_byte_at (input, str_idx) == '\0')) | ||
3838 | return 0; | ||
3839 | return char_len; | ||
3840 | } | ||
3841 | |||
3842 | elem_len = re_string_elem_size_at (input, str_idx); | ||
3843 | if ((elem_len <= 1 && char_len <= 1) || char_len == 0) | ||
3844 | return 0; | ||
3845 | |||
3846 | if (node->type == COMPLEX_BRACKET) | ||
3847 | { | ||
3848 | const re_charset_t *cset = node->opr.mbcset; | ||
3849 | # ifdef _LIBC | ||
3850 | const unsigned char *pin | ||
3851 | = ((const unsigned char *) re_string_get_buffer (input) + str_idx); | ||
3852 | Idx j; | ||
3853 | uint32_t nrules; | ||
3854 | # endif /* _LIBC */ | ||
3855 | int match_len = 0; | ||
3856 | wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars) | ||
3857 | ? re_string_wchar_at (input, str_idx) : 0); | ||
3858 | |||
3859 | /* match with multibyte character? */ | ||
3860 | for (i = 0; i < cset->nmbchars; ++i) | ||
3861 | if (wc == cset->mbchars[i]) | ||
3862 | { | ||
3863 | match_len = char_len; | ||
3864 | goto check_node_accept_bytes_match; | ||
3865 | } | ||
3866 | /* match with character_class? */ | ||
3867 | for (i = 0; i < cset->nchar_classes; ++i) | ||
3868 | { | ||
3869 | wctype_t wt = cset->char_classes[i]; | ||
3870 | if (__iswctype (wc, wt)) | ||
3871 | { | ||
3872 | match_len = char_len; | ||
3873 | goto check_node_accept_bytes_match; | ||
3874 | } | ||
3875 | } | ||
3876 | |||
3877 | # ifdef _LIBC | ||
3878 | nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); | ||
3879 | if (nrules != 0) | ||
3880 | { | ||
3881 | unsigned int in_collseq = 0; | ||
3882 | const int32_t *table, *indirect; | ||
3883 | const unsigned char *weights, *extra; | ||
3884 | const char *collseqwc; | ||
3885 | int32_t idx; | ||
3886 | /* This #include defines a local function! */ | ||
3887 | # include <locale/weight.h> | ||
3888 | |||
3889 | /* match with collating_symbol? */ | ||
3890 | if (cset->ncoll_syms) | ||
3891 | extra = (const unsigned char *) | ||
3892 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); | ||
3893 | for (i = 0; i < cset->ncoll_syms; ++i) | ||
3894 | { | ||
3895 | const unsigned char *coll_sym = extra + cset->coll_syms[i]; | ||
3896 | /* Compare the length of input collating element and | ||
3897 | the length of current collating element. */ | ||
3898 | if (*coll_sym != elem_len) | ||
3899 | continue; | ||
3900 | /* Compare each bytes. */ | ||
3901 | for (j = 0; j < *coll_sym; j++) | ||
3902 | if (pin[j] != coll_sym[1 + j]) | ||
3903 | break; | ||
3904 | if (j == *coll_sym) | ||
3905 | { | ||
3906 | /* Match if every bytes is equal. */ | ||
3907 | match_len = j; | ||
3908 | goto check_node_accept_bytes_match; | ||
3909 | } | ||
3910 | } | ||
3911 | |||
3912 | if (cset->nranges) | ||
3913 | { | ||
3914 | if (elem_len <= char_len) | ||
3915 | { | ||
3916 | collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); | ||
3917 | in_collseq = __collseq_table_lookup (collseqwc, wc); | ||
3918 | } | ||
3919 | else | ||
3920 | in_collseq = find_collation_sequence_value (pin, elem_len); | ||
3921 | } | ||
3922 | /* match with range expression? */ | ||
3923 | for (i = 0; i < cset->nranges; ++i) | ||
3924 | if (cset->range_starts[i] <= in_collseq | ||
3925 | && in_collseq <= cset->range_ends[i]) | ||
3926 | { | ||
3927 | match_len = elem_len; | ||
3928 | goto check_node_accept_bytes_match; | ||
3929 | } | ||
3930 | |||
3931 | /* match with equivalence_class? */ | ||
3932 | if (cset->nequiv_classes) | ||
3933 | { | ||
3934 | const unsigned char *cp = pin; | ||
3935 | table = (const int32_t *) | ||
3936 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); | ||
3937 | weights = (const unsigned char *) | ||
3938 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); | ||
3939 | extra = (const unsigned char *) | ||
3940 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); | ||
3941 | indirect = (const int32_t *) | ||
3942 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); | ||
3943 | idx = findidx (&cp); | ||
3944 | if (idx > 0) | ||
3945 | for (i = 0; i < cset->nequiv_classes; ++i) | ||
3946 | { | ||
3947 | int32_t equiv_class_idx = cset->equiv_classes[i]; | ||
3948 | size_t weight_len = weights[idx]; | ||
3949 | if (weight_len == weights[equiv_class_idx]) | ||
3950 | { | ||
3951 | Idx cnt = 0; | ||
3952 | while (cnt <= weight_len | ||
3953 | && (weights[equiv_class_idx + 1 + cnt] | ||
3954 | == weights[idx + 1 + cnt])) | ||
3955 | ++cnt; | ||
3956 | if (cnt > weight_len) | ||
3957 | { | ||
3958 | match_len = elem_len; | ||
3959 | goto check_node_accept_bytes_match; | ||
3960 | } | ||
3961 | } | ||
3962 | } | ||
3963 | } | ||
3964 | } | ||
3965 | else | ||
3966 | # endif /* _LIBC */ | ||
3967 | { | ||
3968 | /* match with range expression? */ | ||
3969 | #if __GNUC__ >= 2 && ! (__STDC_VERSION__ < 199901L && __STRICT_ANSI__) | ||
3970 | wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'}; | ||
3971 | #else | ||
3972 | wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; | ||
3973 | cmp_buf[2] = wc; | ||
3974 | #endif | ||
3975 | for (i = 0; i < cset->nranges; ++i) | ||
3976 | { | ||
3977 | cmp_buf[0] = cset->range_starts[i]; | ||
3978 | cmp_buf[4] = cset->range_ends[i]; | ||
3979 | if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 | ||
3980 | && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) | ||
3981 | { | ||
3982 | match_len = char_len; | ||
3983 | goto check_node_accept_bytes_match; | ||
3984 | } | ||
3985 | } | ||
3986 | } | ||
3987 | check_node_accept_bytes_match: | ||
3988 | if (!cset->non_match) | ||
3989 | return match_len; | ||
3990 | else | ||
3991 | { | ||
3992 | if (match_len > 0) | ||
3993 | return 0; | ||
3994 | else | ||
3995 | return (elem_len > char_len) ? elem_len : char_len; | ||
3996 | } | ||
3997 | } | ||
3998 | return 0; | ||
3999 | } | ||
4000 | |||
4001 | # ifdef _LIBC | ||
4002 | static unsigned int | ||
4003 | internal_function | ||
4004 | find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len) | ||
4005 | { | ||
4006 | uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); | ||
4007 | if (nrules == 0) | ||
4008 | { | ||
4009 | if (mbs_len == 1) | ||
4010 | { | ||
4011 | /* No valid character. Match it as a single byte character. */ | ||
4012 | const unsigned char *collseq = (const unsigned char *) | ||
4013 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); | ||
4014 | return collseq[mbs[0]]; | ||
4015 | } | ||
4016 | return UINT_MAX; | ||
4017 | } | ||
4018 | else | ||
4019 | { | ||
4020 | int32_t idx; | ||
4021 | const unsigned char *extra = (const unsigned char *) | ||
4022 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); | ||
4023 | int32_t extrasize = (const unsigned char *) | ||
4024 | _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra; | ||
4025 | |||
4026 | for (idx = 0; idx < extrasize;) | ||
4027 | { | ||
4028 | int mbs_cnt; | ||
4029 | bool found = false; | ||
4030 | int32_t elem_mbs_len; | ||
4031 | /* Skip the name of collating element name. */ | ||
4032 | idx = idx + extra[idx] + 1; | ||
4033 | elem_mbs_len = extra[idx++]; | ||
4034 | if (mbs_len == elem_mbs_len) | ||
4035 | { | ||
4036 | for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt) | ||
4037 | if (extra[idx + mbs_cnt] != mbs[mbs_cnt]) | ||
4038 | break; | ||
4039 | if (mbs_cnt == elem_mbs_len) | ||
4040 | /* Found the entry. */ | ||
4041 | found = true; | ||
4042 | } | ||
4043 | /* Skip the byte sequence of the collating element. */ | ||
4044 | idx += elem_mbs_len; | ||
4045 | /* Adjust for the alignment. */ | ||
4046 | idx = (idx + 3) & ~3; | ||
4047 | /* Skip the collation sequence value. */ | ||
4048 | idx += sizeof (uint32_t); | ||
4049 | /* Skip the wide char sequence of the collating element. */ | ||
4050 | idx = idx + sizeof (uint32_t) * (extra[idx] + 1); | ||
4051 | /* If we found the entry, return the sequence value. */ | ||
4052 | if (found) | ||
4053 | return *(uint32_t *) (extra + idx); | ||
4054 | /* Skip the collation sequence value. */ | ||
4055 | idx += sizeof (uint32_t); | ||
4056 | } | ||
4057 | return UINT_MAX; | ||
4058 | } | ||
4059 | } | ||
4060 | # endif /* _LIBC */ | ||
4061 | #endif /* RE_ENABLE_I18N */ | ||
4062 | |||
4063 | /* Check whether the node accepts the byte which is IDX-th | ||
4064 | byte of the INPUT. */ | ||
4065 | |||
4066 | static bool | ||
4067 | internal_function | ||
4068 | check_node_accept (const re_match_context_t *mctx, const re_token_t *node, | ||
4069 | Idx idx) | ||
4070 | { | ||
4071 | unsigned char ch; | ||
4072 | ch = re_string_byte_at (&mctx->input, idx); | ||
4073 | switch (node->type) | ||
4074 | { | ||
4075 | case CHARACTER: | ||
4076 | if (node->opr.c != ch) | ||
4077 | return false; | ||
4078 | break; | ||
4079 | |||
4080 | case SIMPLE_BRACKET: | ||
4081 | if (!bitset_contain (node->opr.sbcset, ch)) | ||
4082 | return false; | ||
4083 | break; | ||
4084 | |||
4085 | #ifdef RE_ENABLE_I18N | ||
4086 | case OP_UTF8_PERIOD: | ||
4087 | if (ch >= ASCII_CHARS) | ||
4088 | return false; | ||
4089 | /* FALLTHROUGH */ | ||
4090 | #endif | ||
4091 | case OP_PERIOD: | ||
4092 | if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE)) | ||
4093 | || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL))) | ||
4094 | return false; | ||
4095 | break; | ||
4096 | |||
4097 | default: | ||
4098 | return false; | ||
4099 | } | ||
4100 | |||
4101 | if (node->constraint) | ||
4102 | { | ||
4103 | /* The node has constraints. Check whether the current context | ||
4104 | satisfies the constraints. */ | ||
4105 | unsigned int context = re_string_context_at (&mctx->input, idx, | ||
4106 | mctx->eflags); | ||
4107 | if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) | ||
4108 | return false; | ||
4109 | } | ||
4110 | |||
4111 | return true; | ||
4112 | } | ||
4113 | |||
4114 | /* Extend the buffers, if the buffers have run out. */ | ||
4115 | |||
4116 | static reg_errcode_t | ||
4117 | internal_function | ||
4118 | extend_buffers (re_match_context_t *mctx) | ||
4119 | { | ||
4120 | reg_errcode_t ret; | ||
4121 | re_string_t *pstr = &mctx->input; | ||
4122 | |||
4123 | /* Avoid overflow. */ | ||
4124 | if (BE (SIZE_MAX / 2 / sizeof (re_dfastate_t *) <= pstr->bufs_len, 0)) | ||
4125 | return REG_ESPACE; | ||
4126 | |||
4127 | /* Double the lengthes of the buffers. */ | ||
4128 | ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); | ||
4129 | if (BE (ret != REG_NOERROR, 0)) | ||
4130 | return ret; | ||
4131 | |||
4132 | if (mctx->state_log != NULL) | ||
4133 | { | ||
4134 | /* And double the length of state_log. */ | ||
4135 | /* XXX We have no indication of the size of this buffer. If this | ||
4136 | allocation fail we have no indication that the state_log array | ||
4137 | does not have the right size. */ | ||
4138 | re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *, | ||
4139 | pstr->bufs_len + 1); | ||
4140 | if (BE (new_array == NULL, 0)) | ||
4141 | return REG_ESPACE; | ||
4142 | mctx->state_log = new_array; | ||
4143 | } | ||
4144 | |||
4145 | /* Then reconstruct the buffers. */ | ||
4146 | if (pstr->icase) | ||
4147 | { | ||
4148 | #ifdef RE_ENABLE_I18N | ||
4149 | if (pstr->mb_cur_max > 1) | ||
4150 | { | ||
4151 | ret = build_wcs_upper_buffer (pstr); | ||
4152 | if (BE (ret != REG_NOERROR, 0)) | ||
4153 | return ret; | ||
4154 | } | ||
4155 | else | ||
4156 | #endif /* RE_ENABLE_I18N */ | ||
4157 | build_upper_buffer (pstr); | ||
4158 | } | ||
4159 | else | ||
4160 | { | ||
4161 | #ifdef RE_ENABLE_I18N | ||
4162 | if (pstr->mb_cur_max > 1) | ||
4163 | build_wcs_buffer (pstr); | ||
4164 | else | ||
4165 | #endif /* RE_ENABLE_I18N */ | ||
4166 | { | ||
4167 | if (pstr->trans != NULL) | ||
4168 | re_string_translate_buffer (pstr); | ||
4169 | } | ||
4170 | } | ||
4171 | return REG_NOERROR; | ||
4172 | } | ||
4173 | |||
4174 | |||
4175 | /* Functions for matching context. */ | ||
4176 | |||
4177 | /* Initialize MCTX. */ | ||
4178 | |||
4179 | static reg_errcode_t | ||
4180 | internal_function | ||
4181 | match_ctx_init (re_match_context_t *mctx, int eflags, Idx n) | ||
4182 | { | ||
4183 | mctx->eflags = eflags; | ||
4184 | mctx->match_last = REG_MISSING; | ||
4185 | if (n > 0) | ||
4186 | { | ||
4187 | /* Avoid overflow. */ | ||
4188 | size_t max_object_size = | ||
4189 | MAX (sizeof (struct re_backref_cache_entry), | ||
4190 | sizeof (re_sub_match_top_t *)); | ||
4191 | if (BE (SIZE_MAX / max_object_size < n, 0)) | ||
4192 | return REG_ESPACE; | ||
4193 | |||
4194 | mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n); | ||
4195 | mctx->sub_tops = re_malloc (re_sub_match_top_t *, n); | ||
4196 | if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0)) | ||
4197 | return REG_ESPACE; | ||
4198 | } | ||
4199 | /* Already zero-ed by the caller. | ||
4200 | else | ||
4201 | mctx->bkref_ents = NULL; | ||
4202 | mctx->nbkref_ents = 0; | ||
4203 | mctx->nsub_tops = 0; */ | ||
4204 | mctx->abkref_ents = n; | ||
4205 | mctx->max_mb_elem_len = 1; | ||
4206 | mctx->asub_tops = n; | ||
4207 | return REG_NOERROR; | ||
4208 | } | ||
4209 | |||
4210 | /* Clean the entries which depend on the current input in MCTX. | ||
4211 | This function must be invoked when the matcher changes the start index | ||
4212 | of the input, or changes the input string. */ | ||
4213 | |||
4214 | static void | ||
4215 | internal_function | ||
4216 | match_ctx_clean (re_match_context_t *mctx) | ||
4217 | { | ||
4218 | Idx st_idx; | ||
4219 | for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx) | ||
4220 | { | ||
4221 | Idx sl_idx; | ||
4222 | re_sub_match_top_t *top = mctx->sub_tops[st_idx]; | ||
4223 | for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx) | ||
4224 | { | ||
4225 | re_sub_match_last_t *last = top->lasts[sl_idx]; | ||
4226 | re_free (last->path.array); | ||
4227 | re_free (last); | ||
4228 | } | ||
4229 | re_free (top->lasts); | ||
4230 | if (top->path) | ||
4231 | { | ||
4232 | re_free (top->path->array); | ||
4233 | re_free (top->path); | ||
4234 | } | ||
4235 | free (top); | ||
4236 | } | ||
4237 | |||
4238 | mctx->nsub_tops = 0; | ||
4239 | mctx->nbkref_ents = 0; | ||
4240 | } | ||
4241 | |||
4242 | /* Free all the memory associated with MCTX. */ | ||
4243 | |||
4244 | static void | ||
4245 | internal_function | ||
4246 | match_ctx_free (re_match_context_t *mctx) | ||
4247 | { | ||
4248 | /* First, free all the memory associated with MCTX->SUB_TOPS. */ | ||
4249 | match_ctx_clean (mctx); | ||
4250 | re_free (mctx->sub_tops); | ||
4251 | re_free (mctx->bkref_ents); | ||
4252 | } | ||
4253 | |||
4254 | /* Add a new backreference entry to MCTX. | ||
4255 | Note that we assume that caller never call this function with duplicate | ||
4256 | entry, and call with STR_IDX which isn't smaller than any existing entry. | ||
4257 | */ | ||
4258 | |||
4259 | static reg_errcode_t | ||
4260 | internal_function | ||
4261 | match_ctx_add_entry (re_match_context_t *mctx, Idx node, Idx str_idx, Idx from, | ||
4262 | Idx to) | ||
4263 | { | ||
4264 | if (mctx->nbkref_ents >= mctx->abkref_ents) | ||
4265 | { | ||
4266 | struct re_backref_cache_entry* new_entry; | ||
4267 | new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry, | ||
4268 | mctx->abkref_ents * 2); | ||
4269 | if (BE (new_entry == NULL, 0)) | ||
4270 | { | ||
4271 | re_free (mctx->bkref_ents); | ||
4272 | return REG_ESPACE; | ||
4273 | } | ||
4274 | mctx->bkref_ents = new_entry; | ||
4275 | memset (mctx->bkref_ents + mctx->nbkref_ents, '\0', | ||
4276 | sizeof (struct re_backref_cache_entry) * mctx->abkref_ents); | ||
4277 | mctx->abkref_ents *= 2; | ||
4278 | } | ||
4279 | if (mctx->nbkref_ents > 0 | ||
4280 | && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx) | ||
4281 | mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1; | ||
4282 | |||
4283 | mctx->bkref_ents[mctx->nbkref_ents].node = node; | ||
4284 | mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx; | ||
4285 | mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from; | ||
4286 | mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to; | ||
4287 | |||
4288 | /* This is a cache that saves negative results of check_dst_limits_calc_pos. | ||
4289 | If bit N is clear, means that this entry won't epsilon-transition to | ||
4290 | an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If | ||
4291 | it is set, check_dst_limits_calc_pos_1 will recurse and try to find one | ||
4292 | such node. | ||
4293 | |||
4294 | A backreference does not epsilon-transition unless it is empty, so set | ||
4295 | to all zeros if FROM != TO. */ | ||
4296 | mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map | ||
4297 | = (from == to ? -1 : 0); | ||
4298 | |||
4299 | mctx->bkref_ents[mctx->nbkref_ents++].more = 0; | ||
4300 | if (mctx->max_mb_elem_len < to - from) | ||
4301 | mctx->max_mb_elem_len = to - from; | ||
4302 | return REG_NOERROR; | ||
4303 | } | ||
4304 | |||
4305 | /* Return the first entry with the same str_idx, or REG_MISSING if none is | ||
4306 | found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */ | ||
4307 | |||
4308 | static Idx | ||
4309 | internal_function | ||
4310 | search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx) | ||
4311 | { | ||
4312 | Idx left, right, mid, last; | ||
4313 | last = right = mctx->nbkref_ents; | ||
4314 | for (left = 0; left < right;) | ||
4315 | { | ||
4316 | mid = (left + right) / 2; | ||
4317 | if (mctx->bkref_ents[mid].str_idx < str_idx) | ||
4318 | left = mid + 1; | ||
4319 | else | ||
4320 | right = mid; | ||
4321 | } | ||
4322 | if (left < last && mctx->bkref_ents[left].str_idx == str_idx) | ||
4323 | return left; | ||
4324 | else | ||
4325 | return REG_MISSING; | ||
4326 | } | ||
4327 | |||
4328 | /* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches | ||
4329 | at STR_IDX. */ | ||
4330 | |||
4331 | static reg_errcode_t | ||
4332 | internal_function | ||
4333 | match_ctx_add_subtop (re_match_context_t *mctx, Idx node, Idx str_idx) | ||
4334 | { | ||
4335 | #ifdef DEBUG | ||
4336 | assert (mctx->sub_tops != NULL); | ||
4337 | assert (mctx->asub_tops > 0); | ||
4338 | #endif | ||
4339 | if (BE (mctx->nsub_tops == mctx->asub_tops, 0)) | ||
4340 | { | ||
4341 | Idx new_asub_tops = mctx->asub_tops * 2; | ||
4342 | re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops, | ||
4343 | re_sub_match_top_t *, | ||
4344 | new_asub_tops); | ||
4345 | if (BE (new_array == NULL, 0)) | ||
4346 | return REG_ESPACE; | ||
4347 | mctx->sub_tops = new_array; | ||
4348 | mctx->asub_tops = new_asub_tops; | ||
4349 | } | ||
4350 | mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t)); | ||
4351 | if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0)) | ||
4352 | return REG_ESPACE; | ||
4353 | mctx->sub_tops[mctx->nsub_tops]->node = node; | ||
4354 | mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx; | ||
4355 | return REG_NOERROR; | ||
4356 | } | ||
4357 | |||
4358 | /* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches | ||
4359 | at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ | ||
4360 | |||
4361 | static re_sub_match_last_t * | ||
4362 | internal_function | ||
4363 | match_ctx_add_sublast (re_sub_match_top_t *subtop, Idx node, Idx str_idx) | ||
4364 | { | ||
4365 | re_sub_match_last_t *new_entry; | ||
4366 | if (BE (subtop->nlasts == subtop->alasts, 0)) | ||
4367 | { | ||
4368 | Idx new_alasts = 2 * subtop->alasts + 1; | ||
4369 | re_sub_match_last_t **new_array = re_realloc (subtop->lasts, | ||
4370 | re_sub_match_last_t *, | ||
4371 | new_alasts); | ||
4372 | if (BE (new_array == NULL, 0)) | ||
4373 | return NULL; | ||
4374 | subtop->lasts = new_array; | ||
4375 | subtop->alasts = new_alasts; | ||
4376 | } | ||
4377 | new_entry = calloc (1, sizeof (re_sub_match_last_t)); | ||
4378 | if (BE (new_entry != NULL, 1)) | ||
4379 | { | ||
4380 | subtop->lasts[subtop->nlasts] = new_entry; | ||
4381 | new_entry->node = node; | ||
4382 | new_entry->str_idx = str_idx; | ||
4383 | ++subtop->nlasts; | ||
4384 | } | ||
4385 | return new_entry; | ||
4386 | } | ||
4387 | |||
4388 | static void | ||
4389 | internal_function | ||
4390 | sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, | ||
4391 | re_dfastate_t **limited_sts, Idx last_node, Idx last_str_idx) | ||
4392 | { | ||
4393 | sctx->sifted_states = sifted_sts; | ||
4394 | sctx->limited_states = limited_sts; | ||
4395 | sctx->last_node = last_node; | ||
4396 | sctx->last_str_idx = last_str_idx; | ||
4397 | re_node_set_init_empty (&sctx->limits); | ||
4398 | } | ||
diff --git a/gl/safe-read.c b/gl/safe-read.c new file mode 100644 index 00000000..b7bf1d5c --- /dev/null +++ b/gl/safe-read.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* An interface to read and write that retries after interrupts. | ||
2 | |||
3 | Copyright (C) 1993, 1994, 1998, 2002, 2003, 2004, 2005, 2006 Free | ||
4 | Software Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | /* Specification. */ | ||
23 | #ifdef SAFE_WRITE | ||
24 | # include "safe-write.h" | ||
25 | #else | ||
26 | # include "safe-read.h" | ||
27 | #endif | ||
28 | |||
29 | /* Get ssize_t. */ | ||
30 | #include <sys/types.h> | ||
31 | #include <unistd.h> | ||
32 | |||
33 | #include <errno.h> | ||
34 | |||
35 | #ifdef EINTR | ||
36 | # define IS_EINTR(x) ((x) == EINTR) | ||
37 | #else | ||
38 | # define IS_EINTR(x) 0 | ||
39 | #endif | ||
40 | |||
41 | #include <limits.h> | ||
42 | |||
43 | #ifdef SAFE_WRITE | ||
44 | # define safe_rw safe_write | ||
45 | # define rw write | ||
46 | #else | ||
47 | # define safe_rw safe_read | ||
48 | # define rw read | ||
49 | # undef const | ||
50 | # define const /* empty */ | ||
51 | #endif | ||
52 | |||
53 | /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if | ||
54 | interrupted. Return the actual number of bytes read(written), zero for EOF, | ||
55 | or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error. */ | ||
56 | size_t | ||
57 | safe_rw (int fd, void const *buf, size_t count) | ||
58 | { | ||
59 | /* Work around a bug in Tru64 5.1. Attempting to read more than | ||
60 | INT_MAX bytes fails with errno == EINVAL. See | ||
61 | <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>. | ||
62 | When decreasing COUNT, keep it block-aligned. */ | ||
63 | enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 }; | ||
64 | |||
65 | for (;;) | ||
66 | { | ||
67 | ssize_t result = rw (fd, buf, count); | ||
68 | |||
69 | if (0 <= result) | ||
70 | return result; | ||
71 | else if (IS_EINTR (errno)) | ||
72 | continue; | ||
73 | else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count) | ||
74 | count = BUGGY_READ_MAXIMUM; | ||
75 | else | ||
76 | return result; | ||
77 | } | ||
78 | } | ||
diff --git a/gl/safe-read.h b/gl/safe-read.h new file mode 100644 index 00000000..3451955a --- /dev/null +++ b/gl/safe-read.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* An interface to read() that retries after interrupts. | ||
2 | Copyright (C) 2002, 2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #include <stddef.h> | ||
19 | |||
20 | #ifdef __cplusplus | ||
21 | extern "C" { | ||
22 | #endif | ||
23 | |||
24 | |||
25 | #define SAFE_READ_ERROR ((size_t) -1) | ||
26 | |||
27 | /* Read up to COUNT bytes at BUF from descriptor FD, retrying if interrupted. | ||
28 | Return the actual number of bytes read, zero for EOF, or SAFE_READ_ERROR | ||
29 | upon error. */ | ||
30 | extern size_t safe_read (int fd, void *buf, size_t count); | ||
31 | |||
32 | |||
33 | #ifdef __cplusplus | ||
34 | } | ||
35 | #endif | ||
diff --git a/gl/safe-write.c b/gl/safe-write.c new file mode 100644 index 00000000..4c375a6c --- /dev/null +++ b/gl/safe-write.c | |||
@@ -0,0 +1,19 @@ | |||
1 | /* An interface to write that retries after interrupts. | ||
2 | Copyright (C) 2002 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #define SAFE_WRITE | ||
19 | #include "safe-read.c" | ||
diff --git a/gl/safe-write.h b/gl/safe-write.h new file mode 100644 index 00000000..c1946362 --- /dev/null +++ b/gl/safe-write.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* An interface to write() that retries after interrupts. | ||
2 | Copyright (C) 2002 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #include <stddef.h> | ||
19 | |||
20 | #define SAFE_WRITE_ERROR ((size_t) -1) | ||
21 | |||
22 | /* Write up to COUNT bytes at BUF to descriptor FD, retrying if interrupted. | ||
23 | Return the actual number of bytes written, zero for EOF, or SAFE_WRITE_ERROR | ||
24 | upon error. */ | ||
25 | extern size_t safe_write (int fd, const void *buf, size_t count); | ||
diff --git a/gl/size_max.h b/gl/size_max.h new file mode 100644 index 00000000..ed0bc137 --- /dev/null +++ b/gl/size_max.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* size_max.h -- declare SIZE_MAX through system headers | ||
2 | Copyright (C) 2005-2006 Free Software Foundation, Inc. | ||
3 | Written by Simon Josefsson. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #ifndef GNULIB_SIZE_MAX_H | ||
20 | #define GNULIB_SIZE_MAX_H | ||
21 | |||
22 | /* Get SIZE_MAX declaration on systems like Solaris 7/8/9. */ | ||
23 | # include <limits.h> | ||
24 | /* Get SIZE_MAX declaration on systems like glibc 2. */ | ||
25 | # if HAVE_STDINT_H | ||
26 | # include <stdint.h> | ||
27 | # endif | ||
28 | /* On systems where these include files don't define it, SIZE_MAX is defined | ||
29 | in config.h. */ | ||
30 | |||
31 | #endif /* GNULIB_SIZE_MAX_H */ | ||
diff --git a/gl/snprintf.c b/gl/snprintf.c new file mode 100644 index 00000000..db1ca9af --- /dev/null +++ b/gl/snprintf.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* Formatted output to strings. | ||
2 | Copyright (C) 2004, 2006 Free Software Foundation, Inc. | ||
3 | Written by Simon Josefsson and Paul Eggert. | ||
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, or (at your option) | ||
8 | 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 along | ||
16 | with this program; if not, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #include <config.h> | ||
20 | |||
21 | #include "snprintf.h" | ||
22 | |||
23 | #include <errno.h> | ||
24 | #include <limits.h> | ||
25 | #include <stdarg.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | |||
29 | #include "vasnprintf.h" | ||
30 | |||
31 | /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */ | ||
32 | #ifndef EOVERFLOW | ||
33 | # define EOVERFLOW E2BIG | ||
34 | #endif | ||
35 | |||
36 | /* Print formatted output to string STR. Similar to sprintf, but | ||
37 | additional length SIZE limit how much is written into STR. Returns | ||
38 | string length of formatted string (which may be larger than SIZE). | ||
39 | STR may be NULL, in which case nothing will be written. On error, | ||
40 | return a negative value. */ | ||
41 | int | ||
42 | snprintf (char *str, size_t size, const char *format, ...) | ||
43 | { | ||
44 | char *output; | ||
45 | size_t len; | ||
46 | size_t lenbuf = size; | ||
47 | va_list args; | ||
48 | |||
49 | va_start (args, format); | ||
50 | output = vasnprintf (str, &lenbuf, format, args); | ||
51 | len = lenbuf; | ||
52 | va_end (args); | ||
53 | |||
54 | if (!output) | ||
55 | return -1; | ||
56 | |||
57 | if (output != str) | ||
58 | { | ||
59 | if (size) | ||
60 | { | ||
61 | size_t pruned_len = (len < size ? len : size - 1); | ||
62 | memcpy (str, output, pruned_len); | ||
63 | str[pruned_len] = '\0'; | ||
64 | } | ||
65 | |||
66 | free (output); | ||
67 | } | ||
68 | |||
69 | if (INT_MAX < len) | ||
70 | { | ||
71 | errno = EOVERFLOW; | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | return len; | ||
76 | } | ||
diff --git a/gl/snprintf.h b/gl/snprintf.h new file mode 100644 index 00000000..5032b9e8 --- /dev/null +++ b/gl/snprintf.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* Formatted output to strings. | ||
2 | Copyright (C) 2004 Free Software Foundation, Inc. | ||
3 | Written by Simon Josefsson. | ||
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, or (at your option) | ||
8 | 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 along | ||
16 | with this program; if not, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #ifndef SNPRINTF_H | ||
20 | #define SNPRINTF_H | ||
21 | |||
22 | /* Get snprintf declaration, if available. */ | ||
23 | #include <stdio.h> | ||
24 | |||
25 | #if defined HAVE_DECL_SNPRINTF && !HAVE_DECL_SNPRINTF | ||
26 | int snprintf (char *str, size_t size, const char *format, ...); | ||
27 | #endif | ||
28 | |||
29 | #endif /* SNPRINTF_H */ | ||
diff --git a/gl/socket_.h b/gl/socket_.h new file mode 100644 index 00000000..8b28b5ed --- /dev/null +++ b/gl/socket_.h | |||
@@ -0,0 +1,70 @@ | |||
1 | /* Provide a sys/socket header file for systems lacking it (read: MinGW). | ||
2 | Copyright (C) 2005, 2006 Free Software Foundation, Inc. | ||
3 | Written by Simon Josefsson. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #ifndef _SYS_SOCKET_H | ||
20 | #define _SYS_SOCKET_H | ||
21 | |||
22 | /* This file is supposed to be used on platforms that lack | ||
23 | sys/socket.h. It is intended to provide definitions and prototypes | ||
24 | needed by an application. | ||
25 | |||
26 | Currently only MinGW is supported. See the gnulib manual regarding | ||
27 | Windows sockets. MinGW has the header files winsock2.h and | ||
28 | ws2tcpip.h that declare the sys/socket.h definitions we need. Note | ||
29 | that you can influence which definitions you get by setting the | ||
30 | WINVER symbol before including these two files. For example, | ||
31 | getaddrinfo is only available if _WIN32_WINNT >= 0x0501 (that | ||
32 | symbol is set indiriectly through WINVER). You can set this by | ||
33 | adding AC_DEFINE(WINVER, 0x0501) to configure.ac. Note that your | ||
34 | code may not run on older Windows releases then. My Windows 2000 | ||
35 | box was not able to run the code, for example. The situation is | ||
36 | slightly confusing because: | ||
37 | http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/getaddrinfo_2.asp | ||
38 | suggests that getaddrinfo should be available on all Windows | ||
39 | releases. */ | ||
40 | |||
41 | |||
42 | #if HAVE_WINSOCK2_H | ||
43 | # include <winsock2.h> | ||
44 | #endif | ||
45 | #if HAVE_WS2TCPIP_H | ||
46 | # include <ws2tcpip.h> | ||
47 | #endif | ||
48 | |||
49 | /* For shutdown(). */ | ||
50 | #if !defined SHUT_RD && defined SD_RECEIVE | ||
51 | # define SHUT_RD SD_RECEIVE | ||
52 | #endif | ||
53 | #if !defined SHUT_WR && defined SD_SEND | ||
54 | # define SHUT_WR SD_SEND | ||
55 | #endif | ||
56 | #if !defined SHUT_RDWR && defined SD_BOTH | ||
57 | # define SHUT_RDWR SD_BOTH | ||
58 | #endif | ||
59 | |||
60 | #if defined _WIN32 || defined __WIN32__ | ||
61 | # define ENOTSOCK WSAENOTSOCK | ||
62 | # define EADDRINUSE WSAEADDRINUSE | ||
63 | # define ENETRESET WSAENETRESET | ||
64 | # define ECONNABORTED WSAECONNABORTED | ||
65 | # define ECONNRESET WSAECONNRESET | ||
66 | # define ENOTCONN WSAENOTCONN | ||
67 | # define ESHUTDOWN WSAESHUTDOWN | ||
68 | #endif | ||
69 | |||
70 | #endif /* _SYS_SOCKET_H */ | ||
diff --git a/gl/stdbool_.h b/gl/stdbool_.h new file mode 100644 index 00000000..efa80ba9 --- /dev/null +++ b/gl/stdbool_.h | |||
@@ -0,0 +1,115 @@ | |||
1 | /* Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. | ||
2 | Written by Bruno Haible <haible@clisp.cons.org>, 2001. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _STDBOOL_H | ||
19 | #define _STDBOOL_H | ||
20 | |||
21 | /* ISO C 99 <stdbool.h> for platforms that lack it. */ | ||
22 | |||
23 | /* Usage suggestions: | ||
24 | |||
25 | Programs that use <stdbool.h> should be aware of some limitations | ||
26 | and standards compliance issues. | ||
27 | |||
28 | Standards compliance: | ||
29 | |||
30 | - <stdbool.h> must be #included before 'bool', 'false', 'true' | ||
31 | can be used. | ||
32 | |||
33 | - You cannot assume that sizeof (bool) == 1. | ||
34 | |||
35 | - Programs should not undefine the macros bool, true, and false, | ||
36 | as C99 lists that as an "obsolescent feature". | ||
37 | |||
38 | Limitations of this substitute, when used in a C89 environment: | ||
39 | |||
40 | - <stdbool.h> must be #included before the '_Bool' type can be used. | ||
41 | |||
42 | - You cannot assume that _Bool is a typedef; it might be a macro. | ||
43 | |||
44 | - In C99, casts and automatic conversions to '_Bool' or 'bool' are | ||
45 | performed in such a way that every nonzero value gets converted | ||
46 | to 'true', and zero gets converted to 'false'. This doesn't work | ||
47 | with this substitute. With this substitute, only the values 0 and 1 | ||
48 | give the expected result when converted to _Bool' or 'bool'. | ||
49 | |||
50 | Also, it is suggested that programs use 'bool' rather than '_Bool'; | ||
51 | this isn't required, but 'bool' is more common. */ | ||
52 | |||
53 | |||
54 | /* 7.16. Boolean type and values */ | ||
55 | |||
56 | /* BeOS <sys/socket.h> already #defines false 0, true 1. We use the same | ||
57 | definitions below, but temporarily we have to #undef them. */ | ||
58 | #ifdef __BEOS__ | ||
59 | # include <OS.h> /* defines bool but not _Bool */ | ||
60 | # undef false | ||
61 | # undef true | ||
62 | #endif | ||
63 | |||
64 | /* For the sake of symbolic names in gdb, we define true and false as | ||
65 | enum constants, not only as macros. | ||
66 | It is tempting to write | ||
67 | typedef enum { false = 0, true = 1 } _Bool; | ||
68 | so that gdb prints values of type 'bool' symbolically. But if we do | ||
69 | this, values of type '_Bool' may promote to 'int' or 'unsigned int' | ||
70 | (see ISO C 99 6.7.2.2.(4)); however, '_Bool' must promote to 'int' | ||
71 | (see ISO C 99 6.3.1.1.(2)). So we add a negative value to the | ||
72 | enum; this ensures that '_Bool' promotes to 'int'. */ | ||
73 | #if defined __cplusplus || defined __BEOS__ | ||
74 | /* A compiler known to have 'bool'. */ | ||
75 | /* If the compiler already has both 'bool' and '_Bool', we can assume they | ||
76 | are the same types. */ | ||
77 | # if !@HAVE__BOOL@ | ||
78 | typedef bool _Bool; | ||
79 | # endif | ||
80 | #else | ||
81 | # if !defined __GNUC__ | ||
82 | /* If @HAVE__BOOL@: | ||
83 | Some HP-UX cc and AIX IBM C compiler versions have compiler bugs when | ||
84 | the built-in _Bool type is used. See | ||
85 | http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html | ||
86 | http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html | ||
87 | http://lists.gnu.org/archive/html/bug-coreutils/2005-10/msg00086.html | ||
88 | Similar bugs are likely with other compilers as well; this file | ||
89 | wouldn't be used if <stdbool.h> was working. | ||
90 | So we override the _Bool type. | ||
91 | If !@HAVE__BOOL@: | ||
92 | Need to define _Bool ourselves. As 'signed char' or as an enum type? | ||
93 | Use of a typedef, with SunPRO C, leads to a stupid | ||
94 | "warning: _Bool is a keyword in ISO C99". | ||
95 | Use of an enum type, with IRIX cc, leads to a stupid | ||
96 | "warning(1185): enumerated type mixed with another type". | ||
97 | The only benefit of the enum type, debuggability, is not important | ||
98 | with these compilers. So use 'signed char' and no typedef. */ | ||
99 | # define _Bool signed char | ||
100 | enum { false = 0, true = 1 }; | ||
101 | # else | ||
102 | /* With this compiler, trust the _Bool type if the compiler has it. */ | ||
103 | # if !@HAVE__BOOL@ | ||
104 | typedef enum { _Bool_must_promote_to_int = -1, false = 0, true = 1 } _Bool; | ||
105 | # endif | ||
106 | # endif | ||
107 | #endif | ||
108 | #define bool _Bool | ||
109 | |||
110 | /* The other macros must be usable in preprocessor directives. */ | ||
111 | #define false 0 | ||
112 | #define true 1 | ||
113 | #define __bool_true_false_are_defined 1 | ||
114 | |||
115 | #endif /* _STDBOOL_H */ | ||
diff --git a/gl/stdint_.h b/gl/stdint_.h new file mode 100644 index 00000000..64ec8c5b --- /dev/null +++ b/gl/stdint_.h | |||
@@ -0,0 +1,489 @@ | |||
1 | /* Copyright (C) 2001-2002, 2004-2007 Free Software Foundation, Inc. | ||
2 | Written by Paul Eggert, Bruno Haible, Sam Steingold, Peter Burwood. | ||
3 | This file is part of gnulib. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #ifndef _GL_STDINT_H | ||
20 | #define _GL_STDINT_H | ||
21 | |||
22 | /* | ||
23 | * ISO C 99 <stdint.h> for platforms that lack it. | ||
24 | * <http://www.opengroup.org/susv3xbd/stdint.h.html> | ||
25 | */ | ||
26 | |||
27 | /* Get those types that are already defined in other system include | ||
28 | files, so that we can "#define int8_t signed char" below without | ||
29 | worrying about a later system include file containing a "typedef | ||
30 | signed char int8_t;" that will get messed up by our macro. Our | ||
31 | macros should all be consistent with the system versions, except | ||
32 | for the "fast" types and macros, which we recommend against using | ||
33 | in public interfaces due to compiler differences. */ | ||
34 | |||
35 | #if @HAVE_STDINT_H@ | ||
36 | # if defined __sgi && ! defined __c99 | ||
37 | /* Bypass IRIX's <stdint.h> if in C89 mode, since it merely annoys users | ||
38 | with "This header file is to be used only for c99 mode compilations" | ||
39 | diagnostics. */ | ||
40 | # define __STDINT_H__ | ||
41 | # endif | ||
42 | /* Other systems may have an incomplete or buggy <stdint.h>. | ||
43 | Include it before <inttypes.h>, since any "#include <stdint.h>" | ||
44 | in <inttypes.h> would reinclude us, skipping our contents because | ||
45 | _GL_STDINT_H is defined. */ | ||
46 | # include @ABSOLUTE_STDINT_H@ | ||
47 | #endif | ||
48 | |||
49 | /* <sys/types.h> defines some of the stdint.h types as well, on glibc, | ||
50 | IRIX 6.5, and OpenBSD 3.8 (via <machine/types.h>). | ||
51 | AIX 5.2 <sys/types.h> isn't needed and causes troubles. | ||
52 | MacOS X 10.4.6 <sys/types.h> includes <stdint.h> (which is us), but | ||
53 | relies on the system <stdint.h> definitions, so include | ||
54 | <sys/types.h> after @ABSOLUTE_STDINT_H@. */ | ||
55 | #if @HAVE_SYS_TYPES_H@ && ! defined _AIX | ||
56 | # include <sys/types.h> | ||
57 | #endif | ||
58 | |||
59 | /* Get LONG_MIN, LONG_MAX, ULONG_MAX. */ | ||
60 | #include <limits.h> | ||
61 | |||
62 | #if @HAVE_INTTYPES_H@ | ||
63 | /* In OpenBSD 3.8, <inttypes.h> includes <machine/types.h>, which defines | ||
64 | int{8,16,32,64}_t, uint{8,16,32,64}_t and __BIT_TYPES_DEFINED__. | ||
65 | <inttypes.h> also defines intptr_t and uintptr_t. */ | ||
66 | # define _GL_JUST_INCLUDE_ABSOLUTE_INTTYPES_H | ||
67 | # include <inttypes.h> | ||
68 | # undef _GL_JUST_INCLUDE_ABSOLUTE_INTTYPES_H | ||
69 | #elif @HAVE_SYS_INTTYPES_H@ | ||
70 | /* Solaris 7 <sys/inttypes.h> has the types except the *_fast*_t types, and | ||
71 | the macros except for *_FAST*_*, INTPTR_MIN, PTRDIFF_MIN, PTRDIFF_MAX. */ | ||
72 | # include <sys/inttypes.h> | ||
73 | #endif | ||
74 | |||
75 | #if @HAVE_SYS_BITYPES_H@ && ! defined __BIT_TYPES_DEFINED__ | ||
76 | /* Linux libc4 >= 4.6.7 and libc5 have a <sys/bitypes.h> that defines | ||
77 | int{8,16,32,64}_t and __BIT_TYPES_DEFINED__. In libc5 >= 5.2.2 it is | ||
78 | included by <sys/types.h>. */ | ||
79 | # include <sys/bitypes.h> | ||
80 | #endif | ||
81 | |||
82 | #if ! defined __cplusplus || defined __STDC_CONSTANT_MACROS | ||
83 | |||
84 | /* Get WCHAR_MIN, WCHAR_MAX. */ | ||
85 | # if ! (defined WCHAR_MIN && defined WCHAR_MAX) | ||
86 | # include <wchar.h> | ||
87 | # endif | ||
88 | |||
89 | #endif | ||
90 | |||
91 | /* Minimum and maximum values for a integer type under the usual assumption. | ||
92 | Return an unspecified value if BITS == 0, adding a check to pacify | ||
93 | picky compilers. */ | ||
94 | |||
95 | #define _STDINT_MIN(signed, bits, zero) \ | ||
96 | ((signed) ? (- ((zero) + 1) << ((bits) ? (bits) - 1 : 0)) : (zero)) | ||
97 | |||
98 | #define _STDINT_MAX(signed, bits, zero) \ | ||
99 | ((signed) \ | ||
100 | ? ~ _STDINT_MIN (signed, bits, zero) \ | ||
101 | : ((((zero) + 1) << ((bits) ? (bits) - 1 : 0)) - 1) * 2 + 1) | ||
102 | |||
103 | /* 7.18.1.1. Exact-width integer types */ | ||
104 | |||
105 | /* Here we assume a standard architecture where the hardware integer | ||
106 | types have 8, 16, 32, optionally 64 bits. */ | ||
107 | |||
108 | #undef int8_t | ||
109 | #undef uint8_t | ||
110 | #define int8_t signed char | ||
111 | #define uint8_t unsigned char | ||
112 | |||
113 | #undef int16_t | ||
114 | #undef uint16_t | ||
115 | #define int16_t short int | ||
116 | #define uint16_t unsigned short int | ||
117 | |||
118 | #undef int32_t | ||
119 | #undef uint32_t | ||
120 | #define int32_t int | ||
121 | #define uint32_t unsigned int | ||
122 | |||
123 | #undef int64_t | ||
124 | #if LONG_MAX >> 31 >> 31 == 1 | ||
125 | # define int64_t long int | ||
126 | #elif defined _MSC_VER | ||
127 | # define int64_t __int64 | ||
128 | #elif @HAVE_LONG_LONG_INT@ | ||
129 | # define int64_t long long int | ||
130 | #endif | ||
131 | |||
132 | #undef uint64_t | ||
133 | #if ULONG_MAX >> 31 >> 31 >> 1 == 1 | ||
134 | # define uint64_t unsigned long int | ||
135 | #elif defined _MSC_VER | ||
136 | # define uint64_t unsigned __int64 | ||
137 | #elif @HAVE_UNSIGNED_LONG_LONG_INT@ | ||
138 | # define uint64_t unsigned long long int | ||
139 | #endif | ||
140 | |||
141 | /* Avoid collision with Solaris 2.5.1 <pthread.h> etc. */ | ||
142 | #define _UINT8_T | ||
143 | #define _UINT32_T | ||
144 | #define _UINT64_T | ||
145 | |||
146 | |||
147 | /* 7.18.1.2. Minimum-width integer types */ | ||
148 | |||
149 | /* Here we assume a standard architecture where the hardware integer | ||
150 | types have 8, 16, 32, optionally 64 bits. Therefore the leastN_t types | ||
151 | are the same as the corresponding N_t types. */ | ||
152 | |||
153 | #undef int_least8_t | ||
154 | #undef uint_least8_t | ||
155 | #undef int_least16_t | ||
156 | #undef uint_least16_t | ||
157 | #undef int_least32_t | ||
158 | #undef uint_least32_t | ||
159 | #undef int_least64_t | ||
160 | #undef uint_least64_t | ||
161 | #define int_least8_t int8_t | ||
162 | #define uint_least8_t uint8_t | ||
163 | #define int_least16_t int16_t | ||
164 | #define uint_least16_t uint16_t | ||
165 | #define int_least32_t int32_t | ||
166 | #define uint_least32_t uint32_t | ||
167 | #ifdef int64_t | ||
168 | # define int_least64_t int64_t | ||
169 | #endif | ||
170 | #ifdef uint64_t | ||
171 | # define uint_least64_t uint64_t | ||
172 | #endif | ||
173 | |||
174 | /* 7.18.1.3. Fastest minimum-width integer types */ | ||
175 | |||
176 | /* Note: Other <stdint.h> substitutes may define these types differently. | ||
177 | It is not recommended to use these types in public header files. */ | ||
178 | |||
179 | /* Here we assume a standard architecture where the hardware integer | ||
180 | types have 8, 16, 32, optionally 64 bits. Therefore the fastN_t types | ||
181 | are taken from the same list of types. Assume that 'long int' | ||
182 | is fast enough for all narrower integers. */ | ||
183 | |||
184 | #undef int_fast8_t | ||
185 | #undef uint_fast8_t | ||
186 | #undef int_fast16_t | ||
187 | #undef uint_fast16_t | ||
188 | #undef int_fast32_t | ||
189 | #undef uint_fast32_t | ||
190 | #undef int_fast64_t | ||
191 | #undef uint_fast64_t | ||
192 | #define int_fast8_t long int | ||
193 | #define uint_fast8_t unsigned int_fast8_t | ||
194 | #define int_fast16_t long int | ||
195 | #define uint_fast16_t unsigned int_fast16_t | ||
196 | #define int_fast32_t long int | ||
197 | #define uint_fast32_t unsigned int_fast32_t | ||
198 | #ifdef int64_t | ||
199 | # define int_fast64_t int64_t | ||
200 | #endif | ||
201 | #ifdef uint64_t | ||
202 | # define uint_fast64_t uint64_t | ||
203 | #endif | ||
204 | |||
205 | /* 7.18.1.4. Integer types capable of holding object pointers */ | ||
206 | |||
207 | #undef intptr_t | ||
208 | #undef uintptr_t | ||
209 | #define intptr_t long int | ||
210 | #define uintptr_t unsigned long int | ||
211 | |||
212 | /* 7.18.1.5. Greatest-width integer types */ | ||
213 | |||
214 | /* Note: These types are compiler dependent. It may be unwise to use them in | ||
215 | public header files. */ | ||
216 | |||
217 | #undef intmax_t | ||
218 | #if @HAVE_LONG_LONG_INT@ && LONG_MAX >> 30 == 1 | ||
219 | # define intmax_t long long int | ||
220 | #elif defined int64_t | ||
221 | # define intmax_t int64_t | ||
222 | #else | ||
223 | # define intmax_t long int | ||
224 | #endif | ||
225 | |||
226 | #undef uintmax_t | ||
227 | #if @HAVE_UNSIGNED_LONG_LONG_INT@ && ULONG_MAX >> 31 == 1 | ||
228 | # define uintmax_t unsigned long long int | ||
229 | #elif defined uint64_t | ||
230 | # define uintmax_t uint64_t | ||
231 | #else | ||
232 | # define uintmax_t unsigned long int | ||
233 | #endif | ||
234 | |||
235 | /* 7.18.2. Limits of specified-width integer types */ | ||
236 | |||
237 | #if ! defined __cplusplus || defined __STDC_LIMIT_MACROS | ||
238 | |||
239 | /* 7.18.2.1. Limits of exact-width integer types */ | ||
240 | |||
241 | /* Here we assume a standard architecture where the hardware integer | ||
242 | types have 8, 16, 32, optionally 64 bits. */ | ||
243 | |||
244 | #undef INT8_MIN | ||
245 | #undef INT8_MAX | ||
246 | #undef UINT8_MAX | ||
247 | #define INT8_MIN (~ INT8_MAX) | ||
248 | #define INT8_MAX 127 | ||
249 | #define UINT8_MAX 255 | ||
250 | |||
251 | #undef INT16_MIN | ||
252 | #undef INT16_MAX | ||
253 | #undef UINT16_MAX | ||
254 | #define INT16_MIN (~ INT16_MAX) | ||
255 | #define INT16_MAX 32767 | ||
256 | #define UINT16_MAX 65535 | ||
257 | |||
258 | #undef INT32_MIN | ||
259 | #undef INT32_MAX | ||
260 | #undef UINT32_MAX | ||
261 | #define INT32_MIN (~ INT32_MAX) | ||
262 | #define INT32_MAX 2147483647 | ||
263 | #define UINT32_MAX 4294967295U | ||
264 | |||
265 | #undef INT64_MIN | ||
266 | #undef INT64_MAX | ||
267 | #ifdef int64_t | ||
268 | # define INT64_MIN (~ INT64_MAX) | ||
269 | # define INT64_MAX INTMAX_C (9223372036854775807) | ||
270 | #endif | ||
271 | |||
272 | #undef UINT64_MAX | ||
273 | #ifdef uint64_t | ||
274 | # define UINT64_MAX UINTMAX_C (18446744073709551615) | ||
275 | #endif | ||
276 | |||
277 | /* 7.18.2.2. Limits of minimum-width integer types */ | ||
278 | |||
279 | /* Here we assume a standard architecture where the hardware integer | ||
280 | types have 8, 16, 32, optionally 64 bits. Therefore the leastN_t types | ||
281 | are the same as the corresponding N_t types. */ | ||
282 | |||
283 | #undef INT_LEAST8_MIN | ||
284 | #undef INT_LEAST8_MAX | ||
285 | #undef UINT_LEAST8_MAX | ||
286 | #define INT_LEAST8_MIN INT8_MIN | ||
287 | #define INT_LEAST8_MAX INT8_MAX | ||
288 | #define UINT_LEAST8_MAX UINT8_MAX | ||
289 | |||
290 | #undef INT_LEAST16_MIN | ||
291 | #undef INT_LEAST16_MAX | ||
292 | #undef UINT_LEAST16_MAX | ||
293 | #define INT_LEAST16_MIN INT16_MIN | ||
294 | #define INT_LEAST16_MAX INT16_MAX | ||
295 | #define UINT_LEAST16_MAX UINT16_MAX | ||
296 | |||
297 | #undef INT_LEAST32_MIN | ||
298 | #undef INT_LEAST32_MAX | ||
299 | #undef UINT_LEAST32_MAX | ||
300 | #define INT_LEAST32_MIN INT32_MIN | ||
301 | #define INT_LEAST32_MAX INT32_MAX | ||
302 | #define UINT_LEAST32_MAX UINT32_MAX | ||
303 | |||
304 | #undef INT_LEAST64_MIN | ||
305 | #undef INT_LEAST64_MAX | ||
306 | #ifdef int64_t | ||
307 | # define INT_LEAST64_MIN INT64_MIN | ||
308 | # define INT_LEAST64_MAX INT64_MAX | ||
309 | #endif | ||
310 | |||
311 | #undef UINT_LEAST64_MAX | ||
312 | #ifdef uint64_t | ||
313 | # define UINT_LEAST64_MAX UINT64_MAX | ||
314 | #endif | ||
315 | |||
316 | /* 7.18.2.3. Limits of fastest minimum-width integer types */ | ||
317 | |||
318 | /* Here we assume a standard architecture where the hardware integer | ||
319 | types have 8, 16, 32, optionally 64 bits. Therefore the fastN_t types | ||
320 | are taken from the same list of types. */ | ||
321 | |||
322 | #undef INT_FAST8_MIN | ||
323 | #undef INT_FAST8_MAX | ||
324 | #undef UINT_FAST8_MAX | ||
325 | #define INT_FAST8_MIN LONG_MIN | ||
326 | #define INT_FAST8_MAX LONG_MAX | ||
327 | #define UINT_FAST8_MAX ULONG_MAX | ||
328 | |||
329 | #undef INT_FAST16_MIN | ||
330 | #undef INT_FAST16_MAX | ||
331 | #undef UINT_FAST16_MAX | ||
332 | #define INT_FAST16_MIN LONG_MIN | ||
333 | #define INT_FAST16_MAX LONG_MAX | ||
334 | #define UINT_FAST16_MAX ULONG_MAX | ||
335 | |||
336 | #undef INT_FAST32_MIN | ||
337 | #undef INT_FAST32_MAX | ||
338 | #undef UINT_FAST32_MAX | ||
339 | #define INT_FAST32_MIN LONG_MIN | ||
340 | #define INT_FAST32_MAX LONG_MAX | ||
341 | #define UINT_FAST32_MAX ULONG_MAX | ||
342 | |||
343 | #undef INT_FAST64_MIN | ||
344 | #undef INT_FAST64_MAX | ||
345 | #ifdef int64_t | ||
346 | # define INT_FAST64_MIN INT64_MIN | ||
347 | # define INT_FAST64_MAX INT64_MAX | ||
348 | #endif | ||
349 | |||
350 | #undef UINT_FAST64_MAX | ||
351 | #ifdef uint64_t | ||
352 | # define UINT_FAST64_MAX UINT64_MAX | ||
353 | #endif | ||
354 | |||
355 | /* 7.18.2.4. Limits of integer types capable of holding object pointers */ | ||
356 | |||
357 | #undef INTPTR_MIN | ||
358 | #undef INTPTR_MAX | ||
359 | #undef UINTPTR_MAX | ||
360 | #define INTPTR_MIN LONG_MIN | ||
361 | #define INTPTR_MAX LONG_MAX | ||
362 | #define UINTPTR_MAX ULONG_MAX | ||
363 | |||
364 | /* 7.18.2.5. Limits of greatest-width integer types */ | ||
365 | |||
366 | #undef INTMAX_MIN | ||
367 | #undef INTMAX_MAX | ||
368 | #define INTMAX_MIN (~ INTMAX_MAX) | ||
369 | #ifdef INT64_MAX | ||
370 | # define INTMAX_MAX INT64_MAX | ||
371 | #else | ||
372 | # define INTMAX_MAX INT32_MAX | ||
373 | #endif | ||
374 | |||
375 | #undef UINTMAX_MAX | ||
376 | #ifdef UINT64_MAX | ||
377 | # define UINTMAX_MAX UINT64_MAX | ||
378 | #else | ||
379 | # define UINTMAX_MAX UINT32_MAX | ||
380 | #endif | ||
381 | |||
382 | /* 7.18.3. Limits of other integer types */ | ||
383 | |||
384 | /* ptrdiff_t limits */ | ||
385 | #undef PTRDIFF_MIN | ||
386 | #undef PTRDIFF_MAX | ||
387 | #define PTRDIFF_MIN \ | ||
388 | _STDINT_MIN (1, @BITSIZEOF_PTRDIFF_T@, 0@PTRDIFF_T_SUFFIX@) | ||
389 | #define PTRDIFF_MAX \ | ||
390 | _STDINT_MAX (1, @BITSIZEOF_PTRDIFF_T@, 0@PTRDIFF_T_SUFFIX@) | ||
391 | |||
392 | /* sig_atomic_t limits */ | ||
393 | #undef SIG_ATOMIC_MIN | ||
394 | #undef SIG_ATOMIC_MAX | ||
395 | #define SIG_ATOMIC_MIN \ | ||
396 | _STDINT_MIN (@HAVE_SIGNED_SIG_ATOMIC_T@, @BITSIZEOF_SIG_ATOMIC_T@, \ | ||
397 | 0@SIG_ATOMIC_T_SUFFIX@) | ||
398 | #define SIG_ATOMIC_MAX \ | ||
399 | _STDINT_MAX (@HAVE_SIGNED_SIG_ATOMIC_T@, @BITSIZEOF_SIG_ATOMIC_T@, \ | ||
400 | 0@SIG_ATOMIC_T_SUFFIX@) | ||
401 | |||
402 | |||
403 | /* size_t limit */ | ||
404 | #undef SIZE_MAX | ||
405 | #define SIZE_MAX _STDINT_MAX (0, @BITSIZEOF_SIZE_T@, 0@SIZE_T_SUFFIX@) | ||
406 | |||
407 | /* wchar_t limits */ | ||
408 | #undef WCHAR_MIN | ||
409 | #undef WCHAR_MAX | ||
410 | #define WCHAR_MIN \ | ||
411 | _STDINT_MIN (@HAVE_SIGNED_WCHAR_T@, @BITSIZEOF_WCHAR_T@, 0@WCHAR_T_SUFFIX@) | ||
412 | #define WCHAR_MAX \ | ||
413 | _STDINT_MAX (@HAVE_SIGNED_WCHAR_T@, @BITSIZEOF_WCHAR_T@, 0@WCHAR_T_SUFFIX@) | ||
414 | |||
415 | /* wint_t limits */ | ||
416 | #undef WINT_MIN | ||
417 | #undef WINT_MAX | ||
418 | #define WINT_MIN \ | ||
419 | _STDINT_MIN (@HAVE_SIGNED_WINT_T@, @BITSIZEOF_WINT_T@, 0@WINT_T_SUFFIX@) | ||
420 | #define WINT_MAX \ | ||
421 | _STDINT_MAX (@HAVE_SIGNED_WINT_T@, @BITSIZEOF_WINT_T@, 0@WINT_T_SUFFIX@) | ||
422 | |||
423 | #endif /* !defined __cplusplus || defined __STDC_LIMIT_MACROS */ | ||
424 | |||
425 | /* 7.18.4. Macros for integer constants */ | ||
426 | |||
427 | #if ! defined __cplusplus || defined __STDC_CONSTANT_MACROS | ||
428 | |||
429 | /* 7.18.4.1. Macros for minimum-width integer constants */ | ||
430 | /* According to ISO C 99 Technical Corrigendum 1 */ | ||
431 | |||
432 | /* Here we assume a standard architecture where the hardware integer | ||
433 | types have 8, 16, 32, optionally 64 bits, and int is 32 bits. */ | ||
434 | |||
435 | #undef INT8_C | ||
436 | #undef UINT8_C | ||
437 | #define INT8_C(x) x | ||
438 | #define UINT8_C(x) x | ||
439 | |||
440 | #undef INT16_C | ||
441 | #undef UINT16_C | ||
442 | #define INT16_C(x) x | ||
443 | #define UINT16_C(x) x | ||
444 | |||
445 | #undef INT32_C | ||
446 | #undef UINT32_C | ||
447 | #define INT32_C(x) x | ||
448 | #define UINT32_C(x) x ## U | ||
449 | |||
450 | #undef INT64_C | ||
451 | #undef UINT64_C | ||
452 | #if LONG_MAX >> 31 >> 31 == 1 | ||
453 | # define INT64_C(x) x##L | ||
454 | #elif defined _MSC_VER | ||
455 | # define INT64_C(x) x##i64 | ||
456 | #elif @HAVE_LONG_LONG_INT@ | ||
457 | # define INT64_C(x) x##LL | ||
458 | #endif | ||
459 | #if ULONG_MAX >> 31 >> 31 >> 1 == 1 | ||
460 | # define UINT64_C(x) x##UL | ||
461 | #elif defined _MSC_VER | ||
462 | # define UINT64_C(x) x##ui64 | ||
463 | #elif @HAVE_UNSIGNED_LONG_LONG_INT@ | ||
464 | # define UINT64_C(x) x##ULL | ||
465 | #endif | ||
466 | |||
467 | /* 7.18.4.2. Macros for greatest-width integer constants */ | ||
468 | |||
469 | #undef INTMAX_C | ||
470 | #if @HAVE_LONG_LONG_INT@ && LONG_MAX >> 30 == 1 | ||
471 | # define INTMAX_C(x) x##LL | ||
472 | #elif defined int64_t | ||
473 | # define INTMAX_C(x) INT64_C(x) | ||
474 | #else | ||
475 | # define INTMAX_C(x) x##L | ||
476 | #endif | ||
477 | |||
478 | #undef UINTMAX_C | ||
479 | #if @HAVE_UNSIGNED_LONG_LONG_INT@ && ULONG_MAX >> 31 == 1 | ||
480 | # define UINTMAX_C(x) x##ULL | ||
481 | #elif defined uint64_t | ||
482 | # define UINTMAX_C(x) UINT64_C(x) | ||
483 | #else | ||
484 | # define UINTMAX_C(x) x##UL | ||
485 | #endif | ||
486 | |||
487 | #endif /* !defined __cplusplus || defined __STDC_CONSTANT_MACROS */ | ||
488 | |||
489 | #endif /* _GL_STDINT_H */ | ||
diff --git a/gl/strcase.h b/gl/strcase.h new file mode 100644 index 00000000..07d4c9a4 --- /dev/null +++ b/gl/strcase.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* Case-insensitive string comparison functions. | ||
2 | Copyright (C) 1995-1996, 2001, 2003, 2005-2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _STRCASE_H | ||
19 | #define _STRCASE_H | ||
20 | |||
21 | #include <stddef.h> | ||
22 | /* Include header files with a possibly conflicting declarations of strcasecmp | ||
23 | before we define it as a macro, so that they will be no-ops if included | ||
24 | after strcasecmp is defined as a macro. */ | ||
25 | #include <string.h> | ||
26 | |||
27 | #ifdef __cplusplus | ||
28 | extern "C" { | ||
29 | #endif | ||
30 | |||
31 | |||
32 | /* No known system has a strcasecmp() function that works correctly in | ||
33 | multibyte locales. Therefore we use our version always. */ | ||
34 | #define strcasecmp rpl_strcasecmp | ||
35 | /* Compare strings S1 and S2, ignoring case, returning less than, equal to or | ||
36 | greater than zero if S1 is lexicographically less than, equal to or greater | ||
37 | than S2. | ||
38 | Note: This function may, in multibyte locales, return 0 for strings of | ||
39 | different lengths! */ | ||
40 | extern int strcasecmp (const char *s1, const char *s2); | ||
41 | |||
42 | /* Compare no more than N characters of strings S1 and S2, ignoring case, | ||
43 | returning less than, equal to or greater than zero if S1 is | ||
44 | lexicographically less than, equal to or greater than S2. | ||
45 | Note: This function can not work correctly in multibyte locales. */ | ||
46 | #if ! HAVE_DECL_STRNCASECMP | ||
47 | extern int strncasecmp (const char *s1, const char *s2, size_t n); | ||
48 | #endif | ||
49 | |||
50 | |||
51 | #ifdef __cplusplus | ||
52 | } | ||
53 | #endif | ||
54 | |||
55 | |||
56 | #endif /* _STRCASE_H */ | ||
diff --git a/gl/strcasecmp.c b/gl/strcasecmp.c new file mode 100644 index 00000000..99d5dd22 --- /dev/null +++ b/gl/strcasecmp.c | |||
@@ -0,0 +1,103 @@ | |||
1 | /* Case-insensitive string comparison function. | ||
2 | Copyright (C) 1998-1999, 2005-2006 Free Software Foundation, Inc. | ||
3 | Written by Bruno Haible <bruno@clisp.org>, 2005, | ||
4 | based on earlier glibc code. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | /* Specification. */ | ||
23 | #include "strcase.h" | ||
24 | |||
25 | #include <ctype.h> | ||
26 | #include <limits.h> | ||
27 | |||
28 | #if HAVE_MBRTOWC | ||
29 | # include "mbuiter.h" | ||
30 | #endif | ||
31 | |||
32 | #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch)) | ||
33 | |||
34 | /* Compare strings S1 and S2, ignoring case, returning less than, equal to or | ||
35 | greater than zero if S1 is lexicographically less than, equal to or greater | ||
36 | than S2. | ||
37 | Note: This function may, in multibyte locales, return 0 for strings of | ||
38 | different lengths! */ | ||
39 | int | ||
40 | strcasecmp (const char *s1, const char *s2) | ||
41 | { | ||
42 | if (s1 == s2) | ||
43 | return 0; | ||
44 | |||
45 | /* Be careful not to look at the entire extent of s1 or s2 until needed. | ||
46 | This is useful because when two strings differ, the difference is | ||
47 | most often already in the very few first characters. */ | ||
48 | #if HAVE_MBRTOWC | ||
49 | if (MB_CUR_MAX > 1) | ||
50 | { | ||
51 | mbui_iterator_t iter1; | ||
52 | mbui_iterator_t iter2; | ||
53 | |||
54 | mbui_init (iter1, s1); | ||
55 | mbui_init (iter2, s2); | ||
56 | |||
57 | while (mbui_avail (iter1) && mbui_avail (iter2)) | ||
58 | { | ||
59 | int cmp = mb_casecmp (mbui_cur (iter1), mbui_cur (iter2)); | ||
60 | |||
61 | if (cmp != 0) | ||
62 | return cmp; | ||
63 | |||
64 | mbui_advance (iter1); | ||
65 | mbui_advance (iter2); | ||
66 | } | ||
67 | if (mbui_avail (iter1)) | ||
68 | /* s2 terminated before s1. */ | ||
69 | return 1; | ||
70 | if (mbui_avail (iter2)) | ||
71 | /* s1 terminated before s2. */ | ||
72 | return -1; | ||
73 | return 0; | ||
74 | } | ||
75 | else | ||
76 | #endif | ||
77 | { | ||
78 | const unsigned char *p1 = (const unsigned char *) s1; | ||
79 | const unsigned char *p2 = (const unsigned char *) s2; | ||
80 | unsigned char c1, c2; | ||
81 | |||
82 | do | ||
83 | { | ||
84 | c1 = TOLOWER (*p1); | ||
85 | c2 = TOLOWER (*p2); | ||
86 | |||
87 | if (c1 == '\0') | ||
88 | break; | ||
89 | |||
90 | ++p1; | ||
91 | ++p2; | ||
92 | } | ||
93 | while (c1 == c2); | ||
94 | |||
95 | if (UCHAR_MAX <= INT_MAX) | ||
96 | return c1 - c2; | ||
97 | else | ||
98 | /* On machines where 'char' and 'int' are types of the same size, the | ||
99 | difference of two 'unsigned char' values - including the sign bit - | ||
100 | doesn't fit in an 'int'. */ | ||
101 | return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0); | ||
102 | } | ||
103 | } | ||
diff --git a/gl/strdup.c b/gl/strdup.c new file mode 100644 index 00000000..17d40d62 --- /dev/null +++ b/gl/strdup.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* Copyright (C) 1991, 1996, 1997, 1998, 2002, 2003, 2004, 2006 Free | ||
2 | Software Foundation, Inc. | ||
3 | |||
4 | This file is part of the GNU C Library. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License along | ||
17 | with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #ifndef _LIBC | ||
21 | # include <config.h> | ||
22 | /* Get specification. */ | ||
23 | # include "strdup.h" | ||
24 | #endif | ||
25 | |||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | |||
29 | #undef __strdup | ||
30 | #ifdef _LIBC | ||
31 | # undef strdup | ||
32 | #endif | ||
33 | |||
34 | #ifndef weak_alias | ||
35 | # define __strdup strdup | ||
36 | #endif | ||
37 | |||
38 | /* Duplicate S, returning an identical malloc'd string. */ | ||
39 | char * | ||
40 | __strdup (const char *s) | ||
41 | { | ||
42 | size_t len = strlen (s) + 1; | ||
43 | void *new = malloc (len); | ||
44 | |||
45 | if (new == NULL) | ||
46 | return NULL; | ||
47 | |||
48 | return (char *) memcpy (new, s, len); | ||
49 | } | ||
50 | #ifdef libc_hidden_def | ||
51 | libc_hidden_def (__strdup) | ||
52 | #endif | ||
53 | #ifdef weak_alias | ||
54 | weak_alias (__strdup, strdup) | ||
55 | #endif | ||
diff --git a/gl/strdup.h b/gl/strdup.h new file mode 100644 index 00000000..73e66e3d --- /dev/null +++ b/gl/strdup.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* strdup.h -- duplicate a string | ||
2 | Copyright (C) 2004, 2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef STRDUP_H_ | ||
19 | #define STRDUP_H_ | ||
20 | |||
21 | /* Get strdup declaration, if available. */ | ||
22 | #include <string.h> | ||
23 | |||
24 | #ifdef __cplusplus | ||
25 | extern "C" { | ||
26 | #endif | ||
27 | |||
28 | |||
29 | #if defined HAVE_DECL_STRDUP && !HAVE_DECL_STRDUP && !defined strdup | ||
30 | /* Duplicate S, returning an identical malloc'd string. */ | ||
31 | extern char *strdup (const char *s); | ||
32 | #endif | ||
33 | |||
34 | |||
35 | #ifdef __cplusplus | ||
36 | } | ||
37 | #endif | ||
38 | |||
39 | #endif /* STRDUP_H_ */ | ||
diff --git a/gl/stripslash.c b/gl/stripslash.c new file mode 100644 index 00000000..342d497c --- /dev/null +++ b/gl/stripslash.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /* stripslash.c -- remove redundant trailing slashes from a file name | ||
2 | |||
3 | Copyright (C) 1990, 2001, 2003-2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #include <config.h> | ||
20 | |||
21 | #include "dirname.h" | ||
22 | |||
23 | /* Remove trailing slashes from FILE. Return true if a trailing slash | ||
24 | was removed. This is useful when using file name completion from a | ||
25 | shell that adds a "/" after directory names (such as tcsh and | ||
26 | bash), because on symlinks to directories, several system calls | ||
27 | have different semantics according to whether a trailing slash is | ||
28 | present. */ | ||
29 | |||
30 | bool | ||
31 | strip_trailing_slashes (char *file) | ||
32 | { | ||
33 | char *base = last_component (file); | ||
34 | char *base_lim; | ||
35 | bool had_slash; | ||
36 | |||
37 | /* last_component returns "" for file system roots, but we need to turn | ||
38 | `///' into `/'. */ | ||
39 | if (! *base) | ||
40 | base = file; | ||
41 | base_lim = base + base_len (base); | ||
42 | had_slash = (*base_lim != '\0'); | ||
43 | *base_lim = '\0'; | ||
44 | return had_slash; | ||
45 | } | ||
diff --git a/gl/strncasecmp.c b/gl/strncasecmp.c new file mode 100644 index 00000000..f59b953a --- /dev/null +++ b/gl/strncasecmp.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* strncasecmp.c -- case insensitive string comparator | ||
2 | Copyright (C) 1998-1999, 2005-2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #include <config.h> | ||
19 | |||
20 | /* Specification. */ | ||
21 | #include "strcase.h" | ||
22 | |||
23 | #include <ctype.h> | ||
24 | #include <limits.h> | ||
25 | |||
26 | #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch)) | ||
27 | |||
28 | /* Compare no more than N bytes of strings S1 and S2, | ||
29 | ignoring case, returning less than, equal to or | ||
30 | greater than zero if S1 is lexicographically less | ||
31 | than, equal to or greater than S2. */ | ||
32 | |||
33 | int | ||
34 | strncasecmp (const char *s1, const char *s2, size_t n) | ||
35 | { | ||
36 | register const unsigned char *p1 = (const unsigned char *) s1; | ||
37 | register const unsigned char *p2 = (const unsigned char *) s2; | ||
38 | unsigned char c1, c2; | ||
39 | |||
40 | if (p1 == p2 || n == 0) | ||
41 | return 0; | ||
42 | |||
43 | do | ||
44 | { | ||
45 | c1 = TOLOWER (*p1); | ||
46 | c2 = TOLOWER (*p2); | ||
47 | |||
48 | if (--n == 0 || c1 == '\0') | ||
49 | break; | ||
50 | |||
51 | ++p1; | ||
52 | ++p2; | ||
53 | } | ||
54 | while (c1 == c2); | ||
55 | |||
56 | if (UCHAR_MAX <= INT_MAX) | ||
57 | return c1 - c2; | ||
58 | else | ||
59 | /* On machines where 'char' and 'int' are types of the same size, the | ||
60 | difference of two 'unsigned char' values - including the sign bit - | ||
61 | doesn't fit in an 'int'. */ | ||
62 | return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0); | ||
63 | } | ||
diff --git a/gl/strndup.c b/gl/strndup.c new file mode 100644 index 00000000..290f494f --- /dev/null +++ b/gl/strndup.c | |||
@@ -0,0 +1,39 @@ | |||
1 | /* A replacement function, for systems that lack strndup. | ||
2 | |||
3 | Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2005, 2006 Free | ||
4 | Software Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify it | ||
7 | under the terms of the GNU General Public License as published by the | ||
8 | Free Software Foundation; either version 2, or (at your option) any | ||
9 | later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | #include "strndup.h" | ||
22 | |||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | |||
26 | #include "strnlen.h" | ||
27 | |||
28 | char * | ||
29 | strndup (char const *s, size_t n) | ||
30 | { | ||
31 | size_t len = strnlen (s, n); | ||
32 | char *new = malloc (len + 1); | ||
33 | |||
34 | if (new == NULL) | ||
35 | return NULL; | ||
36 | |||
37 | new[len] = '\0'; | ||
38 | return memcpy (new, s, len); | ||
39 | } | ||
diff --git a/gl/strndup.h b/gl/strndup.h new file mode 100644 index 00000000..b983dd22 --- /dev/null +++ b/gl/strndup.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* Duplicate a size-bounded string. | ||
2 | Copyright (C) 2003, 2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | /* Get size_t. */ | ||
19 | #include <stddef.h> | ||
20 | /* If HAVE_STRNDUP, get the strndup declaration. | ||
21 | If !HAVE_STRNDUP, include <string.h> now so that it doesn't cause | ||
22 | trouble if included later. */ | ||
23 | #include <string.h> | ||
24 | |||
25 | #if !HAVE_STRNDUP | ||
26 | # undef strndup | ||
27 | # define strndup rpl_strndup | ||
28 | # if !HAVE_DECL_STRNDUP /* Don't risk conflicting declarations. */ | ||
29 | /* Return a newly allocated copy of at most N bytes of STRING. */ | ||
30 | extern char *strndup (const char *string, size_t n); | ||
31 | # endif | ||
32 | #endif | ||
diff --git a/gl/strnlen.c b/gl/strnlen.c new file mode 100644 index 00000000..593fd1b7 --- /dev/null +++ b/gl/strnlen.c | |||
@@ -0,0 +1,31 @@ | |||
1 | /* Find the length of STRING, but scan at most MAXLEN characters. | ||
2 | Copyright (C) 2005, 2006 Free Software Foundation, Inc. | ||
3 | Written by Simon Josefsson. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #include <config.h> | ||
20 | |||
21 | #include "strnlen.h" | ||
22 | |||
23 | /* Find the length of STRING, but scan at most MAXLEN characters. | ||
24 | If no '\0' terminator is found in that many characters, return MAXLEN. */ | ||
25 | |||
26 | size_t | ||
27 | strnlen (const char *string, size_t maxlen) | ||
28 | { | ||
29 | const char *end = memchr (string, '\0', maxlen); | ||
30 | return end ? (size_t) (end - string) : maxlen; | ||
31 | } | ||
diff --git a/gl/strnlen.h b/gl/strnlen.h new file mode 100644 index 00000000..ba74dba7 --- /dev/null +++ b/gl/strnlen.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* Find the length of STRING, but scan at most MAXLEN characters. | ||
2 | Copyright (C) 2005 Free Software Foundation, Inc. | ||
3 | Written by Simon Josefsson. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #ifndef STRNLEN_H | ||
20 | #define STRNLEN_H | ||
21 | |||
22 | /* Get strnlen declaration, if available. */ | ||
23 | #include <string.h> | ||
24 | |||
25 | #if defined HAVE_DECL_STRNLEN && !HAVE_DECL_STRNLEN | ||
26 | /* Find the length (number of bytes) of STRING, but scan at most | ||
27 | MAXLEN bytes. If no '\0' terminator is found in that many bytes, | ||
28 | return MAXLEN. */ | ||
29 | extern size_t strnlen(const char *string, size_t maxlen); | ||
30 | #endif | ||
31 | |||
32 | #endif /* STRNLEN_H */ | ||
diff --git a/gl/strnlen1.c b/gl/strnlen1.c new file mode 100644 index 00000000..422ed9e8 --- /dev/null +++ b/gl/strnlen1.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* Find the length of STRING + 1, but scan at most MAXLEN bytes. | ||
2 | Copyright (C) 2005-2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #include <config.h> | ||
19 | |||
20 | /* Specification. */ | ||
21 | #include "strnlen1.h" | ||
22 | |||
23 | #include <string.h> | ||
24 | |||
25 | /* Find the length of STRING + 1, but scan at most MAXLEN bytes. | ||
26 | If no '\0' terminator is found in that many characters, return MAXLEN. */ | ||
27 | /* This is the same as strnlen (string, maxlen - 1) + 1. */ | ||
28 | size_t | ||
29 | strnlen1 (const char *string, size_t maxlen) | ||
30 | { | ||
31 | const char *end = (const char *) memchr (string, '\0', maxlen); | ||
32 | if (end != NULL) | ||
33 | return end - string + 1; | ||
34 | else | ||
35 | return maxlen; | ||
36 | } | ||
diff --git a/gl/strnlen1.h b/gl/strnlen1.h new file mode 100644 index 00000000..7ce7d0c8 --- /dev/null +++ b/gl/strnlen1.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* Find the length of STRING + 1, but scan at most MAXLEN bytes. | ||
2 | Copyright (C) 2005 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _STRNLEN1_H | ||
19 | #define _STRNLEN1_H | ||
20 | |||
21 | #include <stddef.h> | ||
22 | |||
23 | |||
24 | #ifdef __cplusplus | ||
25 | extern "C" { | ||
26 | #endif | ||
27 | |||
28 | |||
29 | /* Find the length of STRING + 1, but scan at most MAXLEN bytes. | ||
30 | If no '\0' terminator is found in that many characters, return MAXLEN. */ | ||
31 | /* This is the same as strnlen (string, maxlen - 1) + 1. */ | ||
32 | extern size_t strnlen1 (const char *string, size_t maxlen); | ||
33 | |||
34 | |||
35 | #ifdef __cplusplus | ||
36 | } | ||
37 | #endif | ||
38 | |||
39 | |||
40 | #endif /* _STRNLEN1_H */ | ||
diff --git a/gl/unistd--.h b/gl/unistd--.h new file mode 100644 index 00000000..1fe6ce8b --- /dev/null +++ b/gl/unistd--.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* Like unistd.h, but redefine some names to avoid glitches. | ||
2 | |||
3 | Copyright (C) 2005 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Paul Eggert. */ | ||
20 | |||
21 | #include <unistd.h> | ||
22 | #include "unistd-safer.h" | ||
23 | |||
24 | #undef dup | ||
25 | #define dup dup_safer | ||
26 | |||
27 | #undef pipe | ||
28 | #define pipe pipe_safer | ||
diff --git a/gl/unistd-safer.h b/gl/unistd-safer.h new file mode 100644 index 00000000..f95999d3 --- /dev/null +++ b/gl/unistd-safer.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* Invoke unistd-like functions, but avoid some glitches. | ||
2 | |||
3 | Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Paul Eggert. */ | ||
20 | |||
21 | int dup_safer (int); | ||
22 | int fd_safer (int); | ||
23 | int pipe_safer (int[2]); | ||
diff --git a/gl/unistd_.h b/gl/unistd_.h new file mode 100644 index 00000000..36fa6731 --- /dev/null +++ b/gl/unistd_.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* Substitute for and wrapper around <unistd.h>. | ||
2 | Copyright (C) 2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _GL_UNISTD_H | ||
19 | #define _GL_UNISTD_H | ||
20 | |||
21 | #if HAVE_UNISTD_H | ||
22 | # include @ABSOLUTE_UNISTD_H@ | ||
23 | #endif | ||
24 | |||
25 | |||
26 | /* Declare overridden functions. */ | ||
27 | |||
28 | #ifdef __cplusplus | ||
29 | extern "C" { | ||
30 | #endif | ||
31 | |||
32 | #ifdef FCHDIR_REPLACEMENT | ||
33 | |||
34 | /* Change the process' current working directory to the directory on which | ||
35 | the given file descriptor is open. */ | ||
36 | extern int fchdir (int /*fd*/); | ||
37 | |||
38 | # define close rpl_close | ||
39 | extern int close (int); | ||
40 | # define dup rpl_dup | ||
41 | extern int dup (int); | ||
42 | # define dup2 rpl_dup2 | ||
43 | extern int dup2 (int, int); | ||
44 | |||
45 | #endif | ||
46 | |||
47 | #ifdef __cplusplus | ||
48 | } | ||
49 | #endif | ||
50 | |||
51 | |||
52 | #endif /* _GL_UNISTD_H */ | ||
diff --git a/gl/vasnprintf.c b/gl/vasnprintf.c new file mode 100644 index 00000000..0fe2aada --- /dev/null +++ b/gl/vasnprintf.c | |||
@@ -0,0 +1,889 @@ | |||
1 | /* vsprintf with automatic memory allocation. | ||
2 | Copyright (C) 1999, 2002-2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | /* Tell glibc's <stdio.h> to provide a prototype for snprintf(). | ||
19 | This must come before <config.h> because <config.h> may include | ||
20 | <features.h>, and once <features.h> has been included, it's too late. */ | ||
21 | #ifndef _GNU_SOURCE | ||
22 | # define _GNU_SOURCE 1 | ||
23 | #endif | ||
24 | |||
25 | #include <config.h> | ||
26 | #ifndef IN_LIBINTL | ||
27 | # include <alloca.h> | ||
28 | #endif | ||
29 | |||
30 | /* Specification. */ | ||
31 | #if WIDE_CHAR_VERSION | ||
32 | # include "vasnwprintf.h" | ||
33 | #else | ||
34 | # include "vasnprintf.h" | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> /* snprintf(), sprintf() */ | ||
38 | #include <stdlib.h> /* abort(), malloc(), realloc(), free() */ | ||
39 | #include <string.h> /* memcpy(), strlen() */ | ||
40 | #include <errno.h> /* errno */ | ||
41 | #include <limits.h> /* CHAR_BIT */ | ||
42 | #include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ | ||
43 | #if WIDE_CHAR_VERSION | ||
44 | # include "wprintf-parse.h" | ||
45 | #else | ||
46 | # include "printf-parse.h" | ||
47 | #endif | ||
48 | |||
49 | /* Checked size_t computations. */ | ||
50 | #include "xsize.h" | ||
51 | |||
52 | #ifdef HAVE_WCHAR_T | ||
53 | # ifdef HAVE_WCSLEN | ||
54 | # define local_wcslen wcslen | ||
55 | # else | ||
56 | /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid | ||
57 | a dependency towards this library, here is a local substitute. | ||
58 | Define this substitute only once, even if this file is included | ||
59 | twice in the same compilation unit. */ | ||
60 | # ifndef local_wcslen_defined | ||
61 | # define local_wcslen_defined 1 | ||
62 | static size_t | ||
63 | local_wcslen (const wchar_t *s) | ||
64 | { | ||
65 | const wchar_t *ptr; | ||
66 | |||
67 | for (ptr = s; *ptr != (wchar_t) 0; ptr++) | ||
68 | ; | ||
69 | return ptr - s; | ||
70 | } | ||
71 | # endif | ||
72 | # endif | ||
73 | #endif | ||
74 | |||
75 | #if WIDE_CHAR_VERSION | ||
76 | # define VASNPRINTF vasnwprintf | ||
77 | # define CHAR_T wchar_t | ||
78 | # define DIRECTIVE wchar_t_directive | ||
79 | # define DIRECTIVES wchar_t_directives | ||
80 | # define PRINTF_PARSE wprintf_parse | ||
81 | # define USE_SNPRINTF 1 | ||
82 | # if HAVE_DECL__SNWPRINTF | ||
83 | /* On Windows, the function swprintf() has a different signature than | ||
84 | on Unix; we use the _snwprintf() function instead. */ | ||
85 | # define SNPRINTF _snwprintf | ||
86 | # else | ||
87 | /* Unix. */ | ||
88 | # define SNPRINTF swprintf | ||
89 | # endif | ||
90 | #else | ||
91 | # define VASNPRINTF vasnprintf | ||
92 | # define CHAR_T char | ||
93 | # define DIRECTIVE char_directive | ||
94 | # define DIRECTIVES char_directives | ||
95 | # define PRINTF_PARSE printf_parse | ||
96 | # define USE_SNPRINTF (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF) | ||
97 | # if HAVE_DECL__SNPRINTF | ||
98 | /* Windows. */ | ||
99 | # define SNPRINTF _snprintf | ||
100 | # else | ||
101 | /* Unix. */ | ||
102 | # define SNPRINTF snprintf | ||
103 | # endif | ||
104 | #endif | ||
105 | |||
106 | CHAR_T * | ||
107 | VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list args) | ||
108 | { | ||
109 | DIRECTIVES d; | ||
110 | arguments a; | ||
111 | |||
112 | if (PRINTF_PARSE (format, &d, &a) < 0) | ||
113 | { | ||
114 | errno = EINVAL; | ||
115 | return NULL; | ||
116 | } | ||
117 | |||
118 | #define CLEANUP() \ | ||
119 | free (d.dir); \ | ||
120 | if (a.arg) \ | ||
121 | free (a.arg); | ||
122 | |||
123 | if (printf_fetchargs (args, &a) < 0) | ||
124 | { | ||
125 | CLEANUP (); | ||
126 | errno = EINVAL; | ||
127 | return NULL; | ||
128 | } | ||
129 | |||
130 | { | ||
131 | size_t buf_neededlength; | ||
132 | CHAR_T *buf; | ||
133 | CHAR_T *buf_malloced; | ||
134 | const CHAR_T *cp; | ||
135 | size_t i; | ||
136 | DIRECTIVE *dp; | ||
137 | /* Output string accumulator. */ | ||
138 | CHAR_T *result; | ||
139 | size_t allocated; | ||
140 | size_t length; | ||
141 | |||
142 | /* Allocate a small buffer that will hold a directive passed to | ||
143 | sprintf or snprintf. */ | ||
144 | buf_neededlength = | ||
145 | xsum4 (7, d.max_width_length, d.max_precision_length, 6); | ||
146 | #if HAVE_ALLOCA | ||
147 | if (buf_neededlength < 4000 / sizeof (CHAR_T)) | ||
148 | { | ||
149 | buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T)); | ||
150 | buf_malloced = NULL; | ||
151 | } | ||
152 | else | ||
153 | #endif | ||
154 | { | ||
155 | size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T)); | ||
156 | if (size_overflow_p (buf_memsize)) | ||
157 | goto out_of_memory_1; | ||
158 | buf = (CHAR_T *) malloc (buf_memsize); | ||
159 | if (buf == NULL) | ||
160 | goto out_of_memory_1; | ||
161 | buf_malloced = buf; | ||
162 | } | ||
163 | |||
164 | if (resultbuf != NULL) | ||
165 | { | ||
166 | result = resultbuf; | ||
167 | allocated = *lengthp; | ||
168 | } | ||
169 | else | ||
170 | { | ||
171 | result = NULL; | ||
172 | allocated = 0; | ||
173 | } | ||
174 | length = 0; | ||
175 | /* Invariants: | ||
176 | result is either == resultbuf or == NULL or malloc-allocated. | ||
177 | If length > 0, then result != NULL. */ | ||
178 | |||
179 | /* Ensures that allocated >= needed. Aborts through a jump to | ||
180 | out_of_memory if needed is SIZE_MAX or otherwise too big. */ | ||
181 | #define ENSURE_ALLOCATION(needed) \ | ||
182 | if ((needed) > allocated) \ | ||
183 | { \ | ||
184 | size_t memory_size; \ | ||
185 | CHAR_T *memory; \ | ||
186 | \ | ||
187 | allocated = (allocated > 0 ? xtimes (allocated, 2) : 12); \ | ||
188 | if ((needed) > allocated) \ | ||
189 | allocated = (needed); \ | ||
190 | memory_size = xtimes (allocated, sizeof (CHAR_T)); \ | ||
191 | if (size_overflow_p (memory_size)) \ | ||
192 | goto out_of_memory; \ | ||
193 | if (result == resultbuf || result == NULL) \ | ||
194 | memory = (CHAR_T *) malloc (memory_size); \ | ||
195 | else \ | ||
196 | memory = (CHAR_T *) realloc (result, memory_size); \ | ||
197 | if (memory == NULL) \ | ||
198 | goto out_of_memory; \ | ||
199 | if (result == resultbuf && length > 0) \ | ||
200 | memcpy (memory, result, length * sizeof (CHAR_T)); \ | ||
201 | result = memory; \ | ||
202 | } | ||
203 | |||
204 | for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) | ||
205 | { | ||
206 | if (cp != dp->dir_start) | ||
207 | { | ||
208 | size_t n = dp->dir_start - cp; | ||
209 | size_t augmented_length = xsum (length, n); | ||
210 | |||
211 | ENSURE_ALLOCATION (augmented_length); | ||
212 | memcpy (result + length, cp, n * sizeof (CHAR_T)); | ||
213 | length = augmented_length; | ||
214 | } | ||
215 | if (i == d.count) | ||
216 | break; | ||
217 | |||
218 | /* Execute a single directive. */ | ||
219 | if (dp->conversion == '%') | ||
220 | { | ||
221 | size_t augmented_length; | ||
222 | |||
223 | if (!(dp->arg_index == ARG_NONE)) | ||
224 | abort (); | ||
225 | augmented_length = xsum (length, 1); | ||
226 | ENSURE_ALLOCATION (augmented_length); | ||
227 | result[length] = '%'; | ||
228 | length = augmented_length; | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | if (!(dp->arg_index != ARG_NONE)) | ||
233 | abort (); | ||
234 | |||
235 | if (dp->conversion == 'n') | ||
236 | { | ||
237 | switch (a.arg[dp->arg_index].type) | ||
238 | { | ||
239 | case TYPE_COUNT_SCHAR_POINTER: | ||
240 | *a.arg[dp->arg_index].a.a_count_schar_pointer = length; | ||
241 | break; | ||
242 | case TYPE_COUNT_SHORT_POINTER: | ||
243 | *a.arg[dp->arg_index].a.a_count_short_pointer = length; | ||
244 | break; | ||
245 | case TYPE_COUNT_INT_POINTER: | ||
246 | *a.arg[dp->arg_index].a.a_count_int_pointer = length; | ||
247 | break; | ||
248 | case TYPE_COUNT_LONGINT_POINTER: | ||
249 | *a.arg[dp->arg_index].a.a_count_longint_pointer = length; | ||
250 | break; | ||
251 | #ifdef HAVE_LONG_LONG_INT | ||
252 | case TYPE_COUNT_LONGLONGINT_POINTER: | ||
253 | *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; | ||
254 | break; | ||
255 | #endif | ||
256 | default: | ||
257 | abort (); | ||
258 | } | ||
259 | } | ||
260 | else | ||
261 | { | ||
262 | arg_type type = a.arg[dp->arg_index].type; | ||
263 | CHAR_T *p; | ||
264 | unsigned int prefix_count; | ||
265 | int prefixes[2]; | ||
266 | #if !USE_SNPRINTF | ||
267 | size_t tmp_length; | ||
268 | CHAR_T tmpbuf[700]; | ||
269 | CHAR_T *tmp; | ||
270 | |||
271 | /* Allocate a temporary buffer of sufficient size for calling | ||
272 | sprintf. */ | ||
273 | { | ||
274 | size_t width; | ||
275 | size_t precision; | ||
276 | |||
277 | width = 0; | ||
278 | if (dp->width_start != dp->width_end) | ||
279 | { | ||
280 | if (dp->width_arg_index != ARG_NONE) | ||
281 | { | ||
282 | int arg; | ||
283 | |||
284 | if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) | ||
285 | abort (); | ||
286 | arg = a.arg[dp->width_arg_index].a.a_int; | ||
287 | width = (arg < 0 ? (unsigned int) (-arg) : arg); | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | const CHAR_T *digitp = dp->width_start; | ||
292 | |||
293 | do | ||
294 | width = xsum (xtimes (width, 10), *digitp++ - '0'); | ||
295 | while (digitp != dp->width_end); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | precision = 6; | ||
300 | if (dp->precision_start != dp->precision_end) | ||
301 | { | ||
302 | if (dp->precision_arg_index != ARG_NONE) | ||
303 | { | ||
304 | int arg; | ||
305 | |||
306 | if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) | ||
307 | abort (); | ||
308 | arg = a.arg[dp->precision_arg_index].a.a_int; | ||
309 | precision = (arg < 0 ? 0 : arg); | ||
310 | } | ||
311 | else | ||
312 | { | ||
313 | const CHAR_T *digitp = dp->precision_start + 1; | ||
314 | |||
315 | precision = 0; | ||
316 | while (digitp != dp->precision_end) | ||
317 | precision = xsum (xtimes (precision, 10), *digitp++ - '0'); | ||
318 | } | ||
319 | } | ||
320 | |||
321 | switch (dp->conversion) | ||
322 | { | ||
323 | |||
324 | case 'd': case 'i': case 'u': | ||
325 | # ifdef HAVE_LONG_LONG_INT | ||
326 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
327 | tmp_length = | ||
328 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
329 | * 0.30103 /* binary -> decimal */ | ||
330 | ) | ||
331 | + 1; /* turn floor into ceil */ | ||
332 | else | ||
333 | # endif | ||
334 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
335 | tmp_length = | ||
336 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
337 | * 0.30103 /* binary -> decimal */ | ||
338 | ) | ||
339 | + 1; /* turn floor into ceil */ | ||
340 | else | ||
341 | tmp_length = | ||
342 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
343 | * 0.30103 /* binary -> decimal */ | ||
344 | ) | ||
345 | + 1; /* turn floor into ceil */ | ||
346 | if (tmp_length < precision) | ||
347 | tmp_length = precision; | ||
348 | /* Multiply by 2, as an estimate for FLAG_GROUP. */ | ||
349 | tmp_length = xsum (tmp_length, tmp_length); | ||
350 | /* Add 1, to account for a leading sign. */ | ||
351 | tmp_length = xsum (tmp_length, 1); | ||
352 | break; | ||
353 | |||
354 | case 'o': | ||
355 | # ifdef HAVE_LONG_LONG_INT | ||
356 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
357 | tmp_length = | ||
358 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
359 | * 0.333334 /* binary -> octal */ | ||
360 | ) | ||
361 | + 1; /* turn floor into ceil */ | ||
362 | else | ||
363 | # endif | ||
364 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
365 | tmp_length = | ||
366 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
367 | * 0.333334 /* binary -> octal */ | ||
368 | ) | ||
369 | + 1; /* turn floor into ceil */ | ||
370 | else | ||
371 | tmp_length = | ||
372 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
373 | * 0.333334 /* binary -> octal */ | ||
374 | ) | ||
375 | + 1; /* turn floor into ceil */ | ||
376 | if (tmp_length < precision) | ||
377 | tmp_length = precision; | ||
378 | /* Add 1, to account for a leading sign. */ | ||
379 | tmp_length = xsum (tmp_length, 1); | ||
380 | break; | ||
381 | |||
382 | case 'x': case 'X': | ||
383 | # ifdef HAVE_LONG_LONG_INT | ||
384 | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) | ||
385 | tmp_length = | ||
386 | (unsigned int) (sizeof (unsigned long long) * CHAR_BIT | ||
387 | * 0.25 /* binary -> hexadecimal */ | ||
388 | ) | ||
389 | + 1; /* turn floor into ceil */ | ||
390 | else | ||
391 | # endif | ||
392 | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) | ||
393 | tmp_length = | ||
394 | (unsigned int) (sizeof (unsigned long) * CHAR_BIT | ||
395 | * 0.25 /* binary -> hexadecimal */ | ||
396 | ) | ||
397 | + 1; /* turn floor into ceil */ | ||
398 | else | ||
399 | tmp_length = | ||
400 | (unsigned int) (sizeof (unsigned int) * CHAR_BIT | ||
401 | * 0.25 /* binary -> hexadecimal */ | ||
402 | ) | ||
403 | + 1; /* turn floor into ceil */ | ||
404 | if (tmp_length < precision) | ||
405 | tmp_length = precision; | ||
406 | /* Add 2, to account for a leading sign or alternate form. */ | ||
407 | tmp_length = xsum (tmp_length, 2); | ||
408 | break; | ||
409 | |||
410 | case 'f': case 'F': | ||
411 | # ifdef HAVE_LONG_DOUBLE | ||
412 | if (type == TYPE_LONGDOUBLE) | ||
413 | tmp_length = | ||
414 | (unsigned int) (LDBL_MAX_EXP | ||
415 | * 0.30103 /* binary -> decimal */ | ||
416 | * 2 /* estimate for FLAG_GROUP */ | ||
417 | ) | ||
418 | + 1 /* turn floor into ceil */ | ||
419 | + 10; /* sign, decimal point etc. */ | ||
420 | else | ||
421 | # endif | ||
422 | tmp_length = | ||
423 | (unsigned int) (DBL_MAX_EXP | ||
424 | * 0.30103 /* binary -> decimal */ | ||
425 | * 2 /* estimate for FLAG_GROUP */ | ||
426 | ) | ||
427 | + 1 /* turn floor into ceil */ | ||
428 | + 10; /* sign, decimal point etc. */ | ||
429 | tmp_length = xsum (tmp_length, precision); | ||
430 | break; | ||
431 | |||
432 | case 'e': case 'E': case 'g': case 'G': | ||
433 | case 'a': case 'A': | ||
434 | tmp_length = | ||
435 | 12; /* sign, decimal point, exponent etc. */ | ||
436 | tmp_length = xsum (tmp_length, precision); | ||
437 | break; | ||
438 | |||
439 | case 'c': | ||
440 | # if defined HAVE_WINT_T && !WIDE_CHAR_VERSION | ||
441 | if (type == TYPE_WIDE_CHAR) | ||
442 | tmp_length = MB_CUR_MAX; | ||
443 | else | ||
444 | # endif | ||
445 | tmp_length = 1; | ||
446 | break; | ||
447 | |||
448 | case 's': | ||
449 | # ifdef HAVE_WCHAR_T | ||
450 | if (type == TYPE_WIDE_STRING) | ||
451 | { | ||
452 | tmp_length = | ||
453 | local_wcslen (a.arg[dp->arg_index].a.a_wide_string); | ||
454 | |||
455 | # if !WIDE_CHAR_VERSION | ||
456 | tmp_length = xtimes (tmp_length, MB_CUR_MAX); | ||
457 | # endif | ||
458 | } | ||
459 | else | ||
460 | # endif | ||
461 | tmp_length = strlen (a.arg[dp->arg_index].a.a_string); | ||
462 | break; | ||
463 | |||
464 | case 'p': | ||
465 | tmp_length = | ||
466 | (unsigned int) (sizeof (void *) * CHAR_BIT | ||
467 | * 0.25 /* binary -> hexadecimal */ | ||
468 | ) | ||
469 | + 1 /* turn floor into ceil */ | ||
470 | + 2; /* account for leading 0x */ | ||
471 | break; | ||
472 | |||
473 | default: | ||
474 | abort (); | ||
475 | } | ||
476 | |||
477 | if (tmp_length < width) | ||
478 | tmp_length = width; | ||
479 | |||
480 | tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ | ||
481 | } | ||
482 | |||
483 | if (tmp_length <= sizeof (tmpbuf) / sizeof (CHAR_T)) | ||
484 | tmp = tmpbuf; | ||
485 | else | ||
486 | { | ||
487 | size_t tmp_memsize = xtimes (tmp_length, sizeof (CHAR_T)); | ||
488 | |||
489 | if (size_overflow_p (tmp_memsize)) | ||
490 | /* Overflow, would lead to out of memory. */ | ||
491 | goto out_of_memory; | ||
492 | tmp = (CHAR_T *) malloc (tmp_memsize); | ||
493 | if (tmp == NULL) | ||
494 | /* Out of memory. */ | ||
495 | goto out_of_memory; | ||
496 | } | ||
497 | #endif | ||
498 | |||
499 | /* Construct the format string for calling snprintf or | ||
500 | sprintf. */ | ||
501 | p = buf; | ||
502 | *p++ = '%'; | ||
503 | if (dp->flags & FLAG_GROUP) | ||
504 | *p++ = '\''; | ||
505 | if (dp->flags & FLAG_LEFT) | ||
506 | *p++ = '-'; | ||
507 | if (dp->flags & FLAG_SHOWSIGN) | ||
508 | *p++ = '+'; | ||
509 | if (dp->flags & FLAG_SPACE) | ||
510 | *p++ = ' '; | ||
511 | if (dp->flags & FLAG_ALT) | ||
512 | *p++ = '#'; | ||
513 | if (dp->flags & FLAG_ZERO) | ||
514 | *p++ = '0'; | ||
515 | if (dp->width_start != dp->width_end) | ||
516 | { | ||
517 | size_t n = dp->width_end - dp->width_start; | ||
518 | memcpy (p, dp->width_start, n * sizeof (CHAR_T)); | ||
519 | p += n; | ||
520 | } | ||
521 | if (dp->precision_start != dp->precision_end) | ||
522 | { | ||
523 | size_t n = dp->precision_end - dp->precision_start; | ||
524 | memcpy (p, dp->precision_start, n * sizeof (CHAR_T)); | ||
525 | p += n; | ||
526 | } | ||
527 | |||
528 | switch (type) | ||
529 | { | ||
530 | #ifdef HAVE_LONG_LONG_INT | ||
531 | case TYPE_LONGLONGINT: | ||
532 | case TYPE_ULONGLONGINT: | ||
533 | *p++ = 'l'; | ||
534 | /*FALLTHROUGH*/ | ||
535 | #endif | ||
536 | case TYPE_LONGINT: | ||
537 | case TYPE_ULONGINT: | ||
538 | #ifdef HAVE_WINT_T | ||
539 | case TYPE_WIDE_CHAR: | ||
540 | #endif | ||
541 | #ifdef HAVE_WCHAR_T | ||
542 | case TYPE_WIDE_STRING: | ||
543 | #endif | ||
544 | *p++ = 'l'; | ||
545 | break; | ||
546 | #ifdef HAVE_LONG_DOUBLE | ||
547 | case TYPE_LONGDOUBLE: | ||
548 | *p++ = 'L'; | ||
549 | break; | ||
550 | #endif | ||
551 | default: | ||
552 | break; | ||
553 | } | ||
554 | *p = dp->conversion; | ||
555 | #if USE_SNPRINTF | ||
556 | p[1] = '%'; | ||
557 | p[2] = 'n'; | ||
558 | p[3] = '\0'; | ||
559 | #else | ||
560 | p[1] = '\0'; | ||
561 | #endif | ||
562 | |||
563 | /* Construct the arguments for calling snprintf or sprintf. */ | ||
564 | prefix_count = 0; | ||
565 | if (dp->width_arg_index != ARG_NONE) | ||
566 | { | ||
567 | if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) | ||
568 | abort (); | ||
569 | prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int; | ||
570 | } | ||
571 | if (dp->precision_arg_index != ARG_NONE) | ||
572 | { | ||
573 | if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) | ||
574 | abort (); | ||
575 | prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int; | ||
576 | } | ||
577 | |||
578 | #if USE_SNPRINTF | ||
579 | /* Prepare checking whether snprintf returns the count | ||
580 | via %n. */ | ||
581 | ENSURE_ALLOCATION (xsum (length, 1)); | ||
582 | result[length] = '\0'; | ||
583 | #endif | ||
584 | |||
585 | for (;;) | ||
586 | { | ||
587 | size_t maxlen; | ||
588 | int count; | ||
589 | int retcount; | ||
590 | |||
591 | maxlen = allocated - length; | ||
592 | count = -1; | ||
593 | retcount = 0; | ||
594 | |||
595 | #if USE_SNPRINTF | ||
596 | # define SNPRINTF_BUF(arg) \ | ||
597 | switch (prefix_count) \ | ||
598 | { \ | ||
599 | case 0: \ | ||
600 | retcount = SNPRINTF (result + length, maxlen, buf, \ | ||
601 | arg, &count); \ | ||
602 | break; \ | ||
603 | case 1: \ | ||
604 | retcount = SNPRINTF (result + length, maxlen, buf, \ | ||
605 | prefixes[0], arg, &count); \ | ||
606 | break; \ | ||
607 | case 2: \ | ||
608 | retcount = SNPRINTF (result + length, maxlen, buf, \ | ||
609 | prefixes[0], prefixes[1], arg, \ | ||
610 | &count); \ | ||
611 | break; \ | ||
612 | default: \ | ||
613 | abort (); \ | ||
614 | } | ||
615 | #else | ||
616 | # define SNPRINTF_BUF(arg) \ | ||
617 | switch (prefix_count) \ | ||
618 | { \ | ||
619 | case 0: \ | ||
620 | count = sprintf (tmp, buf, arg); \ | ||
621 | break; \ | ||
622 | case 1: \ | ||
623 | count = sprintf (tmp, buf, prefixes[0], arg); \ | ||
624 | break; \ | ||
625 | case 2: \ | ||
626 | count = sprintf (tmp, buf, prefixes[0], prefixes[1],\ | ||
627 | arg); \ | ||
628 | break; \ | ||
629 | default: \ | ||
630 | abort (); \ | ||
631 | } | ||
632 | #endif | ||
633 | |||
634 | switch (type) | ||
635 | { | ||
636 | case TYPE_SCHAR: | ||
637 | { | ||
638 | int arg = a.arg[dp->arg_index].a.a_schar; | ||
639 | SNPRINTF_BUF (arg); | ||
640 | } | ||
641 | break; | ||
642 | case TYPE_UCHAR: | ||
643 | { | ||
644 | unsigned int arg = a.arg[dp->arg_index].a.a_uchar; | ||
645 | SNPRINTF_BUF (arg); | ||
646 | } | ||
647 | break; | ||
648 | case TYPE_SHORT: | ||
649 | { | ||
650 | int arg = a.arg[dp->arg_index].a.a_short; | ||
651 | SNPRINTF_BUF (arg); | ||
652 | } | ||
653 | break; | ||
654 | case TYPE_USHORT: | ||
655 | { | ||
656 | unsigned int arg = a.arg[dp->arg_index].a.a_ushort; | ||
657 | SNPRINTF_BUF (arg); | ||
658 | } | ||
659 | break; | ||
660 | case TYPE_INT: | ||
661 | { | ||
662 | int arg = a.arg[dp->arg_index].a.a_int; | ||
663 | SNPRINTF_BUF (arg); | ||
664 | } | ||
665 | break; | ||
666 | case TYPE_UINT: | ||
667 | { | ||
668 | unsigned int arg = a.arg[dp->arg_index].a.a_uint; | ||
669 | SNPRINTF_BUF (arg); | ||
670 | } | ||
671 | break; | ||
672 | case TYPE_LONGINT: | ||
673 | { | ||
674 | long int arg = a.arg[dp->arg_index].a.a_longint; | ||
675 | SNPRINTF_BUF (arg); | ||
676 | } | ||
677 | break; | ||
678 | case TYPE_ULONGINT: | ||
679 | { | ||
680 | unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint; | ||
681 | SNPRINTF_BUF (arg); | ||
682 | } | ||
683 | break; | ||
684 | #ifdef HAVE_LONG_LONG_INT | ||
685 | case TYPE_LONGLONGINT: | ||
686 | { | ||
687 | long long int arg = a.arg[dp->arg_index].a.a_longlongint; | ||
688 | SNPRINTF_BUF (arg); | ||
689 | } | ||
690 | break; | ||
691 | case TYPE_ULONGLONGINT: | ||
692 | { | ||
693 | unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint; | ||
694 | SNPRINTF_BUF (arg); | ||
695 | } | ||
696 | break; | ||
697 | #endif | ||
698 | case TYPE_DOUBLE: | ||
699 | { | ||
700 | double arg = a.arg[dp->arg_index].a.a_double; | ||
701 | SNPRINTF_BUF (arg); | ||
702 | } | ||
703 | break; | ||
704 | #ifdef HAVE_LONG_DOUBLE | ||
705 | case TYPE_LONGDOUBLE: | ||
706 | { | ||
707 | long double arg = a.arg[dp->arg_index].a.a_longdouble; | ||
708 | SNPRINTF_BUF (arg); | ||
709 | } | ||
710 | break; | ||
711 | #endif | ||
712 | case TYPE_CHAR: | ||
713 | { | ||
714 | int arg = a.arg[dp->arg_index].a.a_char; | ||
715 | SNPRINTF_BUF (arg); | ||
716 | } | ||
717 | break; | ||
718 | #ifdef HAVE_WINT_T | ||
719 | case TYPE_WIDE_CHAR: | ||
720 | { | ||
721 | wint_t arg = a.arg[dp->arg_index].a.a_wide_char; | ||
722 | SNPRINTF_BUF (arg); | ||
723 | } | ||
724 | break; | ||
725 | #endif | ||
726 | case TYPE_STRING: | ||
727 | { | ||
728 | const char *arg = a.arg[dp->arg_index].a.a_string; | ||
729 | SNPRINTF_BUF (arg); | ||
730 | } | ||
731 | break; | ||
732 | #ifdef HAVE_WCHAR_T | ||
733 | case TYPE_WIDE_STRING: | ||
734 | { | ||
735 | const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; | ||
736 | SNPRINTF_BUF (arg); | ||
737 | } | ||
738 | break; | ||
739 | #endif | ||
740 | case TYPE_POINTER: | ||
741 | { | ||
742 | void *arg = a.arg[dp->arg_index].a.a_pointer; | ||
743 | SNPRINTF_BUF (arg); | ||
744 | } | ||
745 | break; | ||
746 | default: | ||
747 | abort (); | ||
748 | } | ||
749 | |||
750 | #if USE_SNPRINTF | ||
751 | /* Portability: Not all implementations of snprintf() | ||
752 | are ISO C 99 compliant. Determine the number of | ||
753 | bytes that snprintf() has produced or would have | ||
754 | produced. */ | ||
755 | if (count >= 0) | ||
756 | { | ||
757 | /* Verify that snprintf() has NUL-terminated its | ||
758 | result. */ | ||
759 | if (count < maxlen && result[length + count] != '\0') | ||
760 | abort (); | ||
761 | /* Portability hack. */ | ||
762 | if (retcount > count) | ||
763 | count = retcount; | ||
764 | } | ||
765 | else | ||
766 | { | ||
767 | /* snprintf() doesn't understand the '%n' | ||
768 | directive. */ | ||
769 | if (p[1] != '\0') | ||
770 | { | ||
771 | /* Don't use the '%n' directive; instead, look | ||
772 | at the snprintf() return value. */ | ||
773 | p[1] = '\0'; | ||
774 | continue; | ||
775 | } | ||
776 | else | ||
777 | { | ||
778 | /* Look at the snprintf() return value. */ | ||
779 | if (retcount < 0) | ||
780 | { | ||
781 | /* HP-UX 10.20 snprintf() is doubly deficient: | ||
782 | It doesn't understand the '%n' directive, | ||
783 | *and* it returns -1 (rather than the length | ||
784 | that would have been required) when the | ||
785 | buffer is too small. */ | ||
786 | size_t bigger_need = | ||
787 | xsum (xtimes (allocated, 2), 12); | ||
788 | ENSURE_ALLOCATION (bigger_need); | ||
789 | continue; | ||
790 | } | ||
791 | else | ||
792 | count = retcount; | ||
793 | } | ||
794 | } | ||
795 | #endif | ||
796 | |||
797 | /* Attempt to handle failure. */ | ||
798 | if (count < 0) | ||
799 | { | ||
800 | if (!(result == resultbuf || result == NULL)) | ||
801 | free (result); | ||
802 | if (buf_malloced != NULL) | ||
803 | free (buf_malloced); | ||
804 | CLEANUP (); | ||
805 | errno = EINVAL; | ||
806 | return NULL; | ||
807 | } | ||
808 | |||
809 | #if !USE_SNPRINTF | ||
810 | if (count >= tmp_length) | ||
811 | /* tmp_length was incorrectly calculated - fix the | ||
812 | code above! */ | ||
813 | abort (); | ||
814 | #endif | ||
815 | |||
816 | /* Make room for the result. */ | ||
817 | if (count >= maxlen) | ||
818 | { | ||
819 | /* Need at least count bytes. But allocate | ||
820 | proportionally, to avoid looping eternally if | ||
821 | snprintf() reports a too small count. */ | ||
822 | size_t n = | ||
823 | xmax (xsum (length, count), xtimes (allocated, 2)); | ||
824 | |||
825 | ENSURE_ALLOCATION (n); | ||
826 | #if USE_SNPRINTF | ||
827 | continue; | ||
828 | #endif | ||
829 | } | ||
830 | |||
831 | #if USE_SNPRINTF | ||
832 | /* The snprintf() result did fit. */ | ||
833 | #else | ||
834 | /* Append the sprintf() result. */ | ||
835 | memcpy (result + length, tmp, count * sizeof (CHAR_T)); | ||
836 | if (tmp != tmpbuf) | ||
837 | free (tmp); | ||
838 | #endif | ||
839 | |||
840 | length += count; | ||
841 | break; | ||
842 | } | ||
843 | } | ||
844 | } | ||
845 | } | ||
846 | |||
847 | /* Add the final NUL. */ | ||
848 | ENSURE_ALLOCATION (xsum (length, 1)); | ||
849 | result[length] = '\0'; | ||
850 | |||
851 | if (result != resultbuf && length + 1 < allocated) | ||
852 | { | ||
853 | /* Shrink the allocated memory if possible. */ | ||
854 | CHAR_T *memory; | ||
855 | |||
856 | memory = (CHAR_T *) realloc (result, (length + 1) * sizeof (CHAR_T)); | ||
857 | if (memory != NULL) | ||
858 | result = memory; | ||
859 | } | ||
860 | |||
861 | if (buf_malloced != NULL) | ||
862 | free (buf_malloced); | ||
863 | CLEANUP (); | ||
864 | *lengthp = length; | ||
865 | /* Note that we can produce a big string of a length > INT_MAX. POSIX | ||
866 | says that snprintf() fails with errno = EOVERFLOW in this case, but | ||
867 | that's only because snprintf() returns an 'int'. This function does | ||
868 | not have this limitation. */ | ||
869 | return result; | ||
870 | |||
871 | out_of_memory: | ||
872 | if (!(result == resultbuf || result == NULL)) | ||
873 | free (result); | ||
874 | if (buf_malloced != NULL) | ||
875 | free (buf_malloced); | ||
876 | out_of_memory_1: | ||
877 | CLEANUP (); | ||
878 | errno = ENOMEM; | ||
879 | return NULL; | ||
880 | } | ||
881 | } | ||
882 | |||
883 | #undef SNPRINTF | ||
884 | #undef USE_SNPRINTF | ||
885 | #undef PRINTF_PARSE | ||
886 | #undef DIRECTIVES | ||
887 | #undef DIRECTIVE | ||
888 | #undef CHAR_T | ||
889 | #undef VASNPRINTF | ||
diff --git a/gl/vasnprintf.h b/gl/vasnprintf.h new file mode 100644 index 00000000..894008ca --- /dev/null +++ b/gl/vasnprintf.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* vsprintf with automatic memory allocation. | ||
2 | Copyright (C) 2002-2004 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _VASNPRINTF_H | ||
19 | #define _VASNPRINTF_H | ||
20 | |||
21 | /* Get va_list. */ | ||
22 | #include <stdarg.h> | ||
23 | |||
24 | /* Get size_t. */ | ||
25 | #include <stddef.h> | ||
26 | |||
27 | #ifndef __attribute__ | ||
28 | /* This feature is available in gcc versions 2.5 and later. */ | ||
29 | # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ | ||
30 | # define __attribute__(Spec) /* empty */ | ||
31 | # endif | ||
32 | /* The __-protected variants of `format' and `printf' attributes | ||
33 | are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ | ||
34 | # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) | ||
35 | # define __format__ format | ||
36 | # define __printf__ printf | ||
37 | # endif | ||
38 | #endif | ||
39 | |||
40 | #ifdef __cplusplus | ||
41 | extern "C" { | ||
42 | #endif | ||
43 | |||
44 | /* Write formatted output to a string dynamically allocated with malloc(). | ||
45 | You can pass a preallocated buffer for the result in RESULTBUF and its | ||
46 | size in *LENGTHP; otherwise you pass RESULTBUF = NULL. | ||
47 | If successful, return the address of the string (this may be = RESULTBUF | ||
48 | if no dynamic memory allocation was necessary) and set *LENGTHP to the | ||
49 | number of resulting bytes, excluding the trailing NUL. Upon error, set | ||
50 | errno and return NULL. | ||
51 | |||
52 | When dynamic memory allocation occurs, the preallocated buffer is left | ||
53 | alone (with possibly modified contents). This makes it possible to use | ||
54 | a statically allocated or stack-allocated buffer, like this: | ||
55 | |||
56 | char buf[100]; | ||
57 | size_t len = sizeof (buf); | ||
58 | char *output = vasnprintf (buf, &len, format, args); | ||
59 | if (output == NULL) | ||
60 | ... error handling ...; | ||
61 | else | ||
62 | { | ||
63 | ... use the output string ...; | ||
64 | if (output != buf) | ||
65 | free (output); | ||
66 | } | ||
67 | */ | ||
68 | extern char * asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...) | ||
69 | __attribute__ ((__format__ (__printf__, 3, 4))); | ||
70 | extern char * vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) | ||
71 | __attribute__ ((__format__ (__printf__, 3, 0))); | ||
72 | |||
73 | #ifdef __cplusplus | ||
74 | } | ||
75 | #endif | ||
76 | |||
77 | #endif /* _VASNPRINTF_H */ | ||
diff --git a/gl/vasprintf.c b/gl/vasprintf.c new file mode 100644 index 00000000..82470734 --- /dev/null +++ b/gl/vasprintf.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* Formatted output to strings. | ||
2 | Copyright (C) 1999, 2002, 2006 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #include <config.h> | ||
19 | |||
20 | /* Specification. */ | ||
21 | #include "vasprintf.h" | ||
22 | |||
23 | #include <errno.h> | ||
24 | #include <limits.h> | ||
25 | #include <stdlib.h> | ||
26 | |||
27 | #include "vasnprintf.h" | ||
28 | |||
29 | /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */ | ||
30 | #ifndef EOVERFLOW | ||
31 | # define EOVERFLOW E2BIG | ||
32 | #endif | ||
33 | |||
34 | int | ||
35 | vasprintf (char **resultp, const char *format, va_list args) | ||
36 | { | ||
37 | size_t length; | ||
38 | char *result = vasnprintf (NULL, &length, format, args); | ||
39 | if (result == NULL) | ||
40 | return -1; | ||
41 | |||
42 | if (length > INT_MAX) | ||
43 | { | ||
44 | free (result); | ||
45 | errno = EOVERFLOW; | ||
46 | return -1; | ||
47 | } | ||
48 | |||
49 | *resultp = result; | ||
50 | /* Return the number of resulting bytes, excluding the trailing NUL. */ | ||
51 | return length; | ||
52 | } | ||
diff --git a/gl/vasprintf.h b/gl/vasprintf.h new file mode 100644 index 00000000..ab5515ce --- /dev/null +++ b/gl/vasprintf.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* vsprintf with automatic memory allocation. | ||
2 | Copyright (C) 2002-2003 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _VASPRINTF_H | ||
19 | #define _VASPRINTF_H | ||
20 | |||
21 | #if HAVE_VASPRINTF | ||
22 | |||
23 | /* Get asprintf(), vasprintf() declarations. */ | ||
24 | #include <stdio.h> | ||
25 | |||
26 | #else | ||
27 | |||
28 | /* Get va_list. */ | ||
29 | #include <stdarg.h> | ||
30 | |||
31 | #ifndef __attribute__ | ||
32 | /* This feature is available in gcc versions 2.5 and later. */ | ||
33 | # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ | ||
34 | # define __attribute__(Spec) /* empty */ | ||
35 | # endif | ||
36 | /* The __-protected variants of `format' and `printf' attributes | ||
37 | are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ | ||
38 | # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) | ||
39 | # define __format__ format | ||
40 | # define __printf__ printf | ||
41 | # endif | ||
42 | #endif | ||
43 | |||
44 | #ifdef __cplusplus | ||
45 | extern "C" { | ||
46 | #endif | ||
47 | |||
48 | /* Write formatted output to a string dynamically allocated with malloc(). | ||
49 | If the memory allocation succeeds, store the address of the string in | ||
50 | *RESULT and return the number of resulting bytes, excluding the trailing | ||
51 | NUL. Upon memory allocation error, or some other error, return -1. */ | ||
52 | extern int asprintf (char **result, const char *format, ...) | ||
53 | __attribute__ ((__format__ (__printf__, 2, 3))); | ||
54 | extern int vasprintf (char **result, const char *format, va_list args) | ||
55 | __attribute__ ((__format__ (__printf__, 2, 0))); | ||
56 | |||
57 | #ifdef __cplusplus | ||
58 | } | ||
59 | #endif | ||
60 | |||
61 | #endif | ||
62 | |||
63 | #endif /* _VASPRINTF_H */ | ||
diff --git a/gl/vsnprintf.c b/gl/vsnprintf.c new file mode 100644 index 00000000..af567d2c --- /dev/null +++ b/gl/vsnprintf.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* Formatted output to strings. | ||
2 | Copyright (C) 2004, 2006 Free Software Foundation, Inc. | ||
3 | Written by Simon Josefsson and Yoann Vandoorselaere <yoann@prelude-ids.org>. | ||
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, or (at your option) | ||
8 | 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 along | ||
16 | with this program; if not, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #ifdef HAVE_CONFIG_H | ||
20 | # include <config.h> | ||
21 | #endif | ||
22 | |||
23 | /* Specification. */ | ||
24 | #include "vsnprintf.h" | ||
25 | |||
26 | #include <errno.h> | ||
27 | #include <limits.h> | ||
28 | #include <stdarg.h> | ||
29 | #include <stdio.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <string.h> | ||
32 | |||
33 | #include "vasnprintf.h" | ||
34 | |||
35 | /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */ | ||
36 | #ifndef EOVERFLOW | ||
37 | # define EOVERFLOW E2BIG | ||
38 | #endif | ||
39 | |||
40 | /* Print formatted output to string STR. Similar to vsprintf, but | ||
41 | additional length SIZE limit how much is written into STR. Returns | ||
42 | string length of formatted string (which may be larger than SIZE). | ||
43 | STR may be NULL, in which case nothing will be written. On error, | ||
44 | return a negative value. */ | ||
45 | int | ||
46 | vsnprintf (char *str, size_t size, const char *format, va_list args) | ||
47 | { | ||
48 | char *output; | ||
49 | size_t len; | ||
50 | size_t lenbuf = size; | ||
51 | |||
52 | output = vasnprintf (str, &lenbuf, format, args); | ||
53 | len = lenbuf; | ||
54 | |||
55 | if (!output) | ||
56 | return -1; | ||
57 | |||
58 | if (output != str) | ||
59 | { | ||
60 | if (size) | ||
61 | { | ||
62 | size_t pruned_len = (len < size ? len : size - 1); | ||
63 | memcpy (str, output, pruned_len); | ||
64 | str[pruned_len] = '\0'; | ||
65 | } | ||
66 | |||
67 | free (output); | ||
68 | } | ||
69 | |||
70 | if (len > INT_MAX) | ||
71 | { | ||
72 | errno = EOVERFLOW; | ||
73 | return -1; | ||
74 | } | ||
75 | |||
76 | return len; | ||
77 | } | ||
diff --git a/gl/vsnprintf.h b/gl/vsnprintf.h new file mode 100644 index 00000000..f80c77a9 --- /dev/null +++ b/gl/vsnprintf.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* Formatted output to strings. | ||
2 | Copyright (C) 2004 Free Software Foundation, Inc. | ||
3 | Written by Simon Josefsson and Yoann Vandoorselaere <yoann@prelude-ids.org>. | ||
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, or (at your option) | ||
8 | 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 along | ||
16 | with this program; if not, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #ifndef VSNPRINTF_H | ||
20 | #define VSNPRINTF_H | ||
21 | |||
22 | #include <stdarg.h> | ||
23 | |||
24 | /* Get vsnprintf declaration, if available. */ | ||
25 | #include <stdio.h> | ||
26 | |||
27 | #if defined HAVE_DECL_VSNPRINTF && !HAVE_DECL_VSNPRINTF | ||
28 | int vsnprintf (char *str, size_t size, const char *format, va_list args); | ||
29 | #endif | ||
30 | |||
31 | #endif /* VSNPRINTF_H */ | ||
diff --git a/gl/wchar_.h b/gl/wchar_.h new file mode 100644 index 00000000..6813a211 --- /dev/null +++ b/gl/wchar_.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* A substitute for ISO C99 <wchar.h>, for platforms that have issues. | ||
2 | |||
3 | Copyright (C) 2007 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Eric Blake. */ | ||
20 | |||
21 | /* | ||
22 | * ISO C 99 <wchar.h> for platforms that have issues. | ||
23 | * <http://www.opengroup.org/susv3xbd/wchar.h.html> | ||
24 | * | ||
25 | * For now, this just ensures proper prerequisite inclusion order. | ||
26 | */ | ||
27 | |||
28 | #ifndef _GL_WCHAR_H | ||
29 | #define _GL_WCHAR_H | ||
30 | |||
31 | /* Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before | ||
32 | <wchar.h>. | ||
33 | BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be | ||
34 | included before <wchar.h>. */ | ||
35 | #include <stddef.h> | ||
36 | #include <stdio.h> | ||
37 | #include <time.h> | ||
38 | |||
39 | /* Include the original <wchar.h>. */ | ||
40 | #include @ABSOLUTE_WCHAR_H@ | ||
41 | |||
42 | #endif /* _GL_WCHAR_H */ | ||
diff --git a/gl/wctype_.h b/gl/wctype_.h new file mode 100644 index 00000000..1297c61e --- /dev/null +++ b/gl/wctype_.h | |||
@@ -0,0 +1,154 @@ | |||
1 | /* A substitute for ISO C99 <wctype.h>, for platforms that lack it. | ||
2 | |||
3 | Copyright (C) 2006, 2007 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | /* Written by Bruno Haible and Paul Eggert. */ | ||
20 | |||
21 | /* | ||
22 | * ISO C 99 <wctype.h> for platforms that lack it. | ||
23 | * <http://www.opengroup.org/susv3xbd/wctype.h.html> | ||
24 | * | ||
25 | * iswctype, towctrans, towlower, towupper, wctrans, wctype, | ||
26 | * wctrans_t, and wctype_t are not yet implemented. | ||
27 | */ | ||
28 | |||
29 | #ifndef _GL_WCTYPE_H | ||
30 | #define _GL_WCTYPE_H | ||
31 | |||
32 | #if @HAVE_WINT_T@ | ||
33 | /* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. | ||
34 | Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before | ||
35 | <wchar.h>. | ||
36 | BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be | ||
37 | included before <wchar.h>. */ | ||
38 | # include <stddef.h> | ||
39 | # include <stdio.h> | ||
40 | # include <time.h> | ||
41 | # include <wchar.h> | ||
42 | typedef wint_t __wctype_wint_t; | ||
43 | #else | ||
44 | typedef int __wctype_wint_t; | ||
45 | #endif | ||
46 | |||
47 | /* Include the original <wctype.h> if it exists. | ||
48 | BeOS 5 has the functions but no <wctype.h>. */ | ||
49 | #if @HAVE_WCTYPE_H@ | ||
50 | # include @ABSOLUTE_WCTYPE_H@ | ||
51 | #endif | ||
52 | |||
53 | /* FreeBSD 4.4 to 4.11 has <wctype.h> but lacks the functions. | ||
54 | Assume all 12 functions are implemented the same way, or not at all. */ | ||
55 | #if ! HAVE_ISWCNTRL | ||
56 | |||
57 | /* IRIX 5.3 has macros but no functions, its isw* macros refer to an | ||
58 | undefined variable _ctmp_ and to <ctype.h> macros like _P, and they | ||
59 | refer to system functions like _iswctype that are not in the | ||
60 | standard C library. Rather than try to get ancient buggy | ||
61 | implementations like this to work, just disable them. */ | ||
62 | # undef iswalnum | ||
63 | # undef iswalpha | ||
64 | # undef iswblank | ||
65 | # undef iswcntrl | ||
66 | # undef iswdigit | ||
67 | # undef iswgraph | ||
68 | # undef iswlower | ||
69 | # undef iswprint | ||
70 | # undef iswpunct | ||
71 | # undef iswspace | ||
72 | # undef iswupper | ||
73 | # undef iswxdigit | ||
74 | |||
75 | static inline int | ||
76 | iswalnum (__wctype_wint_t wc) | ||
77 | { | ||
78 | return ((wc >= '0' && wc <= '9') | ||
79 | || ((wc & ~0x20) >= 'A' && (wc & ~0x20) <= 'Z')); | ||
80 | } | ||
81 | |||
82 | static inline int | ||
83 | iswalpha (__wctype_wint_t wc) | ||
84 | { | ||
85 | return (wc & ~0x20) >= 'A' && (wc & ~0x20) <= 'Z'; | ||
86 | } | ||
87 | |||
88 | static inline int | ||
89 | iswblank (__wctype_wint_t wc) | ||
90 | { | ||
91 | return wc == ' ' || wc == '\t'; | ||
92 | } | ||
93 | |||
94 | static inline int | ||
95 | iswcntrl (__wctype_wint_t wc) | ||
96 | { | ||
97 | return (wc & ~0x1f) == 0 || wc == 0x7f; | ||
98 | } | ||
99 | |||
100 | static inline int | ||
101 | iswdigit (__wctype_wint_t wc) | ||
102 | { | ||
103 | return wc >= '0' && wc <= '9'; | ||
104 | } | ||
105 | |||
106 | static inline int | ||
107 | iswgraph (__wctype_wint_t wc) | ||
108 | { | ||
109 | return wc >= '!' && wc <= '~'; | ||
110 | } | ||
111 | |||
112 | static inline int | ||
113 | iswlower (__wctype_wint_t wc) | ||
114 | { | ||
115 | return wc >= 'a' && wc <= 'z'; | ||
116 | } | ||
117 | |||
118 | static inline int | ||
119 | iswprint (__wctype_wint_t wc) | ||
120 | { | ||
121 | return wc >= ' ' && wc <= '~'; | ||
122 | } | ||
123 | |||
124 | static inline int | ||
125 | iswpunct (__wctype_wint_t wc) | ||
126 | { | ||
127 | return (wc >= '!' && wc <= '~' | ||
128 | && !((wc >= '0' && wc <= '9') | ||
129 | || ((wc & ~0x20) >= 'A' && (wc & ~0x20) <= 'Z'))); | ||
130 | } | ||
131 | |||
132 | static inline int | ||
133 | iswspace (__wctype_wint_t wc) | ||
134 | { | ||
135 | return (wc == ' ' || wc == '\t' | ||
136 | || wc == '\n' || wc == '\v' || wc == '\f' || wc == '\r'); | ||
137 | } | ||
138 | |||
139 | static inline int | ||
140 | iswupper (__wctype_wint_t wc) | ||
141 | { | ||
142 | return wc >= 'A' && wc <= 'Z'; | ||
143 | } | ||
144 | |||
145 | static inline int | ||
146 | iswxdigit (__wctype_wint_t wc) | ||
147 | { | ||
148 | return ((wc >= '0' && wc <= '9') | ||
149 | || ((wc & ~0x20) >= 'A' && (wc & ~0x20) <= 'F')); | ||
150 | } | ||
151 | |||
152 | # endif /* ! HAVE_ISWCNTRL */ | ||
153 | |||
154 | #endif /* _GL_WCTYPE_H */ | ||
diff --git a/gl/wcwidth.h b/gl/wcwidth.h new file mode 100644 index 00000000..8ed5ff8c --- /dev/null +++ b/gl/wcwidth.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* Determine the number of screen columns needed for a character. | ||
2 | Copyright (C) 2006, 2007 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
17 | |||
18 | #ifndef _gl_WCWIDTH_H | ||
19 | #define _gl_WCWIDTH_H | ||
20 | |||
21 | #if HAVE_WCHAR_T | ||
22 | |||
23 | /* Get wcwidth if available, along with wchar_t. */ | ||
24 | # include <wchar.h> | ||
25 | |||
26 | /* Get iswprint. */ | ||
27 | # include <wctype.h> | ||
28 | |||
29 | # ifndef HAVE_DECL_WCWIDTH | ||
30 | "this configure-time declaration test was not run" | ||
31 | # endif | ||
32 | # ifndef wcwidth | ||
33 | # if !HAVE_WCWIDTH | ||
34 | |||
35 | /* wcwidth doesn't exist, so assume all printable characters have | ||
36 | width 1. */ | ||
37 | static inline int | ||
38 | wcwidth (wchar_t wc) | ||
39 | { | ||
40 | return wc == 0 ? 0 : iswprint (wc) ? 1 : -1; | ||
41 | } | ||
42 | |||
43 | # elif !HAVE_DECL_WCWIDTH | ||
44 | |||
45 | /* wcwidth exists but is not declared. */ | ||
46 | extern | ||
47 | # ifdef __cplusplus | ||
48 | "C" | ||
49 | # endif | ||
50 | int wcwidth (int /* actually wchar_t */); | ||
51 | |||
52 | # endif | ||
53 | # endif | ||
54 | |||
55 | #endif /* HAVE_WCHAR_T */ | ||
56 | |||
57 | #endif /* _gl_WCWIDTH_H */ | ||
diff --git a/gl/xalloc-die.c b/gl/xalloc-die.c new file mode 100644 index 00000000..090f060d --- /dev/null +++ b/gl/xalloc-die.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* Report a memory allocation failure and exit. | ||
2 | |||
3 | Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2006 Free | ||
4 | Software Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #include <config.h> | ||
21 | |||
22 | #include "xalloc.h" | ||
23 | |||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include "error.h" | ||
27 | #include "exitfail.h" | ||
28 | |||
29 | #include "gettext.h" | ||
30 | #define _(msgid) gettext (msgid) | ||
31 | |||
32 | void | ||
33 | xalloc_die (void) | ||
34 | { | ||
35 | error (exit_failure, 0, "%s", _("memory exhausted")); | ||
36 | |||
37 | /* The `noreturn' cannot be given to error, since it may return if | ||
38 | its first argument is 0. To help compilers understand the | ||
39 | xalloc_die does not return, call abort. Also, the abort is a | ||
40 | safety feature if exit_failure is 0 (which shouldn't happen). */ | ||
41 | abort (); | ||
42 | } | ||
diff --git a/gl/xalloc.h b/gl/xalloc.h new file mode 100644 index 00000000..17ab5142 --- /dev/null +++ b/gl/xalloc.h | |||
@@ -0,0 +1,267 @@ | |||
1 | /* xalloc.h -- malloc with out-of-memory checking | ||
2 | |||
3 | Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, | ||
4 | 1999, 2000, 2003, 2004, 2006 Free Software Foundation, Inc. | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2, or (at your option) | ||
9 | any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software Foundation, | ||
18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
19 | |||
20 | #ifndef XALLOC_H_ | ||
21 | # define XALLOC_H_ | ||
22 | |||
23 | # include <stddef.h> | ||
24 | |||
25 | |||
26 | # ifdef __cplusplus | ||
27 | extern "C" { | ||
28 | # endif | ||
29 | |||
30 | |||
31 | # ifndef __attribute__ | ||
32 | # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ | ||
33 | # define __attribute__(x) | ||
34 | # endif | ||
35 | # endif | ||
36 | |||
37 | # ifndef ATTRIBUTE_NORETURN | ||
38 | # define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) | ||
39 | # endif | ||
40 | |||
41 | /* This function is always triggered when memory is exhausted. | ||
42 | It must be defined by the application, either explicitly | ||
43 | or by using gnulib's xalloc-die module. This is the | ||
44 | function to call when one wants the program to die because of a | ||
45 | memory allocation failure. */ | ||
46 | extern void xalloc_die (void) ATTRIBUTE_NORETURN; | ||
47 | |||
48 | void *xmalloc (size_t s); | ||
49 | void *xzalloc (size_t s); | ||
50 | void *xcalloc (size_t n, size_t s); | ||
51 | void *xrealloc (void *p, size_t s); | ||
52 | void *x2realloc (void *p, size_t *pn); | ||
53 | void *xmemdup (void const *p, size_t s); | ||
54 | char *xstrdup (char const *str); | ||
55 | |||
56 | /* Return 1 if an array of N objects, each of size S, cannot exist due | ||
57 | to size arithmetic overflow. S must be positive and N must be | ||
58 | nonnegative. This is a macro, not an inline function, so that it | ||
59 | works correctly even when SIZE_MAX < N. | ||
60 | |||
61 | By gnulib convention, SIZE_MAX represents overflow in size | ||
62 | calculations, so the conservative dividend to use here is | ||
63 | SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value. | ||
64 | However, malloc (SIZE_MAX) fails on all known hosts where | ||
65 | sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for | ||
66 | exactly-SIZE_MAX allocations on such hosts; this avoids a test and | ||
67 | branch when S is known to be 1. */ | ||
68 | # define xalloc_oversized(n, s) \ | ||
69 | ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n)) | ||
70 | |||
71 | |||
72 | /* In the following macros, T must be an elementary or structure/union or | ||
73 | typedef'ed type, or a pointer to such a type. To apply one of the | ||
74 | following macros to a function pointer or array type, you need to typedef | ||
75 | it first and use the typedef name. */ | ||
76 | |||
77 | /* Allocate an object of type T dynamically, with error checking. */ | ||
78 | /* extern t *XMALLOC (typename t); */ | ||
79 | # define XMALLOC(t) ((t *) xmalloc (sizeof (t))) | ||
80 | |||
81 | /* Allocate memory for N elements of type T, with error checking. */ | ||
82 | /* extern t *XNMALLOC (size_t n, typename t); */ | ||
83 | # define XNMALLOC(n, t) \ | ||
84 | ((t *) (sizeof (t) == 1 ? xmalloc (n) : xnmalloc (n, sizeof (t)))) | ||
85 | |||
86 | /* Allocate an object of type T dynamically, with error checking, | ||
87 | and zero it. */ | ||
88 | /* extern t *XZALLOC (typename t); */ | ||
89 | # define XZALLOC(t) ((t *) xzalloc (sizeof (t))) | ||
90 | |||
91 | /* Allocate memory for N elements of type T, with error checking, | ||
92 | and zero it. */ | ||
93 | /* extern t *XCALLOC (size_t n, typename t); */ | ||
94 | # define XCALLOC(n, t) \ | ||
95 | ((t *) (sizeof (t) == 1 ? xzalloc (n) : xcalloc (n, sizeof (t)))) | ||
96 | |||
97 | |||
98 | # if HAVE_INLINE | ||
99 | # define static_inline static inline | ||
100 | # else | ||
101 | void *xnmalloc (size_t n, size_t s); | ||
102 | void *xnrealloc (void *p, size_t n, size_t s); | ||
103 | void *x2nrealloc (void *p, size_t *pn, size_t s); | ||
104 | char *xcharalloc (size_t n); | ||
105 | # endif | ||
106 | |||
107 | # ifdef static_inline | ||
108 | |||
109 | /* Allocate an array of N objects, each with S bytes of memory, | ||
110 | dynamically, with error checking. S must be nonzero. */ | ||
111 | |||
112 | static_inline void * | ||
113 | xnmalloc (size_t n, size_t s) | ||
114 | { | ||
115 | if (xalloc_oversized (n, s)) | ||
116 | xalloc_die (); | ||
117 | return xmalloc (n * s); | ||
118 | } | ||
119 | |||
120 | /* Change the size of an allocated block of memory P to an array of N | ||
121 | objects each of S bytes, with error checking. S must be nonzero. */ | ||
122 | |||
123 | static_inline void * | ||
124 | xnrealloc (void *p, size_t n, size_t s) | ||
125 | { | ||
126 | if (xalloc_oversized (n, s)) | ||
127 | xalloc_die (); | ||
128 | return xrealloc (p, n * s); | ||
129 | } | ||
130 | |||
131 | /* If P is null, allocate a block of at least *PN such objects; | ||
132 | otherwise, reallocate P so that it contains more than *PN objects | ||
133 | each of S bytes. *PN must be nonzero unless P is null, and S must | ||
134 | be nonzero. Set *PN to the new number of objects, and return the | ||
135 | pointer to the new block. *PN is never set to zero, and the | ||
136 | returned pointer is never null. | ||
137 | |||
138 | Repeated reallocations are guaranteed to make progress, either by | ||
139 | allocating an initial block with a nonzero size, or by allocating a | ||
140 | larger block. | ||
141 | |||
142 | In the following implementation, nonzero sizes are doubled so that | ||
143 | repeated reallocations have O(N log N) overall cost rather than | ||
144 | O(N**2) cost, but the specification for this function does not | ||
145 | guarantee that sizes are doubled. | ||
146 | |||
147 | Here is an example of use: | ||
148 | |||
149 | int *p = NULL; | ||
150 | size_t used = 0; | ||
151 | size_t allocated = 0; | ||
152 | |||
153 | void | ||
154 | append_int (int value) | ||
155 | { | ||
156 | if (used == allocated) | ||
157 | p = x2nrealloc (p, &allocated, sizeof *p); | ||
158 | p[used++] = value; | ||
159 | } | ||
160 | |||
161 | This causes x2nrealloc to allocate a block of some nonzero size the | ||
162 | first time it is called. | ||
163 | |||
164 | To have finer-grained control over the initial size, set *PN to a | ||
165 | nonzero value before calling this function with P == NULL. For | ||
166 | example: | ||
167 | |||
168 | int *p = NULL; | ||
169 | size_t used = 0; | ||
170 | size_t allocated = 0; | ||
171 | size_t allocated1 = 1000; | ||
172 | |||
173 | void | ||
174 | append_int (int value) | ||
175 | { | ||
176 | if (used == allocated) | ||
177 | { | ||
178 | p = x2nrealloc (p, &allocated1, sizeof *p); | ||
179 | allocated = allocated1; | ||
180 | } | ||
181 | p[used++] = value; | ||
182 | } | ||
183 | |||
184 | */ | ||
185 | |||
186 | static_inline void * | ||
187 | x2nrealloc (void *p, size_t *pn, size_t s) | ||
188 | { | ||
189 | size_t n = *pn; | ||
190 | |||
191 | if (! p) | ||
192 | { | ||
193 | if (! n) | ||
194 | { | ||
195 | /* The approximate size to use for initial small allocation | ||
196 | requests, when the invoking code specifies an old size of | ||
197 | zero. 64 bytes is the largest "small" request for the | ||
198 | GNU C library malloc. */ | ||
199 | enum { DEFAULT_MXFAST = 64 }; | ||
200 | |||
201 | n = DEFAULT_MXFAST / s; | ||
202 | n += !n; | ||
203 | } | ||
204 | } | ||
205 | else | ||
206 | { | ||
207 | if (((size_t) -1) / 2 / s < n) | ||
208 | xalloc_die (); | ||
209 | n *= 2; | ||
210 | } | ||
211 | |||
212 | *pn = n; | ||
213 | return xrealloc (p, n * s); | ||
214 | } | ||
215 | |||
216 | /* Return a pointer to a new buffer of N bytes. This is like xmalloc, | ||
217 | except it returns char *. */ | ||
218 | |||
219 | static_inline char * | ||
220 | xcharalloc (size_t n) | ||
221 | { | ||
222 | return XNMALLOC (n, char); | ||
223 | } | ||
224 | |||
225 | # endif | ||
226 | |||
227 | # ifdef __cplusplus | ||
228 | } | ||
229 | |||
230 | /* C++ does not allow conversions from void * to other pointer types | ||
231 | without a cast. Use templates to work around the problem when | ||
232 | possible. */ | ||
233 | |||
234 | template <typename T> inline T * | ||
235 | xrealloc (T *p, size_t s) | ||
236 | { | ||
237 | return (T *) xrealloc ((void *) p, s); | ||
238 | } | ||
239 | |||
240 | template <typename T> inline T * | ||
241 | xnrealloc (T *p, size_t n, size_t s) | ||
242 | { | ||
243 | return (T *) xnrealloc ((void *) p, n, s); | ||
244 | } | ||
245 | |||
246 | template <typename T> inline T * | ||
247 | x2realloc (T *p, size_t *pn) | ||
248 | { | ||
249 | return (T *) x2realloc ((void *) p, pn); | ||
250 | } | ||
251 | |||
252 | template <typename T> inline T * | ||
253 | x2nrealloc (T *p, size_t *pn, size_t s) | ||
254 | { | ||
255 | return (T *) x2nrealloc ((void *) p, pn, s); | ||
256 | } | ||
257 | |||
258 | template <typename T> inline T * | ||
259 | xmemdup (T const *p, size_t s) | ||
260 | { | ||
261 | return (T *) xmemdup ((void const *) p, s); | ||
262 | } | ||
263 | |||
264 | # endif | ||
265 | |||
266 | |||
267 | #endif /* !XALLOC_H_ */ | ||
diff --git a/gl/xmalloc.c b/gl/xmalloc.c new file mode 100644 index 00000000..318e0ddb --- /dev/null +++ b/gl/xmalloc.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* xmalloc.c -- malloc with out of memory checking | ||
2 | |||
3 | Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, | ||
4 | 1999, 2000, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, | ||
5 | Inc. | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2, or (at your option) | ||
10 | any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software Foundation, | ||
19 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
20 | |||
21 | #include <config.h> | ||
22 | |||
23 | #if ! HAVE_INLINE | ||
24 | # define static_inline | ||
25 | #endif | ||
26 | #include "xalloc.h" | ||
27 | #undef static_inline | ||
28 | |||
29 | #include <stdlib.h> | ||
30 | #include <string.h> | ||
31 | |||
32 | #ifndef SIZE_MAX | ||
33 | # define SIZE_MAX ((size_t) -1) | ||
34 | #endif | ||
35 | |||
36 | /* 1 if calloc is known to be compatible with GNU calloc. This | ||
37 | matters if we are not also using the calloc module, which defines | ||
38 | HAVE_CALLOC and supports the GNU API even on non-GNU platforms. */ | ||
39 | #if defined HAVE_CALLOC || defined __GLIBC__ | ||
40 | enum { HAVE_GNU_CALLOC = 1 }; | ||
41 | #else | ||
42 | enum { HAVE_GNU_CALLOC = 0 }; | ||
43 | #endif | ||
44 | |||
45 | /* Allocate N bytes of memory dynamically, with error checking. */ | ||
46 | |||
47 | void * | ||
48 | xmalloc (size_t n) | ||
49 | { | ||
50 | void *p = malloc (n); | ||
51 | if (!p && n != 0) | ||
52 | xalloc_die (); | ||
53 | return p; | ||
54 | } | ||
55 | |||
56 | /* Change the size of an allocated block of memory P to N bytes, | ||
57 | with error checking. */ | ||
58 | |||
59 | void * | ||
60 | xrealloc (void *p, size_t n) | ||
61 | { | ||
62 | p = realloc (p, n); | ||
63 | if (!p && n != 0) | ||
64 | xalloc_die (); | ||
65 | return p; | ||
66 | } | ||
67 | |||
68 | /* If P is null, allocate a block of at least *PN bytes; otherwise, | ||
69 | reallocate P so that it contains more than *PN bytes. *PN must be | ||
70 | nonzero unless P is null. Set *PN to the new block's size, and | ||
71 | return the pointer to the new block. *PN is never set to zero, and | ||
72 | the returned pointer is never null. */ | ||
73 | |||
74 | void * | ||
75 | x2realloc (void *p, size_t *pn) | ||
76 | { | ||
77 | return x2nrealloc (p, pn, 1); | ||
78 | } | ||
79 | |||
80 | /* Allocate S bytes of zeroed memory dynamically, with error checking. | ||
81 | There's no need for xnzalloc (N, S), since it would be equivalent | ||
82 | to xcalloc (N, S). */ | ||
83 | |||
84 | void * | ||
85 | xzalloc (size_t s) | ||
86 | { | ||
87 | return memset (xmalloc (s), 0, s); | ||
88 | } | ||
89 | |||
90 | /* Allocate zeroed memory for N elements of S bytes, with error | ||
91 | checking. S must be nonzero. */ | ||
92 | |||
93 | void * | ||
94 | xcalloc (size_t n, size_t s) | ||
95 | { | ||
96 | void *p; | ||
97 | /* Test for overflow, since some calloc implementations don't have | ||
98 | proper overflow checks. But omit overflow and size-zero tests if | ||
99 | HAVE_GNU_CALLOC, since GNU calloc catches overflow and never | ||
100 | returns NULL if successful. */ | ||
101 | if ((! HAVE_GNU_CALLOC && xalloc_oversized (n, s)) | ||
102 | || (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0))) | ||
103 | xalloc_die (); | ||
104 | return p; | ||
105 | } | ||
106 | |||
107 | /* Clone an object P of size S, with error checking. There's no need | ||
108 | for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any | ||
109 | need for an arithmetic overflow check. */ | ||
110 | |||
111 | void * | ||
112 | xmemdup (void const *p, size_t s) | ||
113 | { | ||
114 | return memcpy (xmalloc (s), p, s); | ||
115 | } | ||
116 | |||
117 | /* Clone STRING. */ | ||
118 | |||
119 | char * | ||
120 | xstrdup (char const *string) | ||
121 | { | ||
122 | return xmemdup (string, strlen (string) + 1); | ||
123 | } | ||
diff --git a/gl/xsize.h b/gl/xsize.h new file mode 100644 index 00000000..341fb16c --- /dev/null +++ b/gl/xsize.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /* xsize.h -- Checked size_t computations. | ||
2 | |||
3 | Copyright (C) 2003 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #ifndef _XSIZE_H | ||
20 | #define _XSIZE_H | ||
21 | |||
22 | /* Get size_t. */ | ||
23 | #include <stddef.h> | ||
24 | |||
25 | /* Get SIZE_MAX. */ | ||
26 | #include <limits.h> | ||
27 | #if HAVE_STDINT_H | ||
28 | # include <stdint.h> | ||
29 | #endif | ||
30 | |||
31 | /* The size of memory objects is often computed through expressions of | ||
32 | type size_t. Example: | ||
33 | void* p = malloc (header_size + n * element_size). | ||
34 | These computations can lead to overflow. When this happens, malloc() | ||
35 | returns a piece of memory that is way too small, and the program then | ||
36 | crashes while attempting to fill the memory. | ||
37 | To avoid this, the functions and macros in this file check for overflow. | ||
38 | The convention is that SIZE_MAX represents overflow. | ||
39 | malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc | ||
40 | implementation that uses mmap --, it's recommended to use size_overflow_p() | ||
41 | or size_in_bounds_p() before invoking malloc(). | ||
42 | The example thus becomes: | ||
43 | size_t size = xsum (header_size, xtimes (n, element_size)); | ||
44 | void *p = (size_in_bounds_p (size) ? malloc (size) : NULL); | ||
45 | */ | ||
46 | |||
47 | /* Convert an arbitrary value >= 0 to type size_t. */ | ||
48 | #define xcast_size_t(N) \ | ||
49 | ((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX) | ||
50 | |||
51 | /* Sum of two sizes, with overflow check. */ | ||
52 | static inline size_t | ||
53 | #if __GNUC__ >= 3 | ||
54 | __attribute__ ((__pure__)) | ||
55 | #endif | ||
56 | xsum (size_t size1, size_t size2) | ||
57 | { | ||
58 | size_t sum = size1 + size2; | ||
59 | return (sum >= size1 ? sum : SIZE_MAX); | ||
60 | } | ||
61 | |||
62 | /* Sum of three sizes, with overflow check. */ | ||
63 | static inline size_t | ||
64 | #if __GNUC__ >= 3 | ||
65 | __attribute__ ((__pure__)) | ||
66 | #endif | ||
67 | xsum3 (size_t size1, size_t size2, size_t size3) | ||
68 | { | ||
69 | return xsum (xsum (size1, size2), size3); | ||
70 | } | ||
71 | |||
72 | /* Sum of four sizes, with overflow check. */ | ||
73 | static inline size_t | ||
74 | #if __GNUC__ >= 3 | ||
75 | __attribute__ ((__pure__)) | ||
76 | #endif | ||
77 | xsum4 (size_t size1, size_t size2, size_t size3, size_t size4) | ||
78 | { | ||
79 | return xsum (xsum (xsum (size1, size2), size3), size4); | ||
80 | } | ||
81 | |||
82 | /* Maximum of two sizes, with overflow check. */ | ||
83 | static inline size_t | ||
84 | #if __GNUC__ >= 3 | ||
85 | __attribute__ ((__pure__)) | ||
86 | #endif | ||
87 | xmax (size_t size1, size_t size2) | ||
88 | { | ||
89 | /* No explicit check is needed here, because for any n: | ||
90 | max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX. */ | ||
91 | return (size1 >= size2 ? size1 : size2); | ||
92 | } | ||
93 | |||
94 | /* Multiplication of a count with an element size, with overflow check. | ||
95 | The count must be >= 0 and the element size must be > 0. | ||
96 | This is a macro, not an inline function, so that it works correctly even | ||
97 | when N is of a wider tupe and N > SIZE_MAX. */ | ||
98 | #define xtimes(N, ELSIZE) \ | ||
99 | ((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX) | ||
100 | |||
101 | /* Check for overflow. */ | ||
102 | #define size_overflow_p(SIZE) \ | ||
103 | ((SIZE) == SIZE_MAX) | ||
104 | /* Check against overflow. */ | ||
105 | #define size_in_bounds_p(SIZE) \ | ||
106 | ((SIZE) != SIZE_MAX) | ||
107 | |||
108 | #endif /* _XSIZE_H */ | ||
diff --git a/gl/xstrndup.c b/gl/xstrndup.c new file mode 100644 index 00000000..afcbc1ab --- /dev/null +++ b/gl/xstrndup.c | |||
@@ -0,0 +1,37 @@ | |||
1 | /* Duplicate a bounded initial segment of a string, with out-of-memory | ||
2 | checking. | ||
3 | Copyright (C) 2003, 2006 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #include <config.h> | ||
20 | |||
21 | /* Specification. */ | ||
22 | #include "xstrndup.h" | ||
23 | |||
24 | #include "strndup.h" | ||
25 | #include "xalloc.h" | ||
26 | |||
27 | /* Return a newly allocated copy of at most N bytes of STRING. | ||
28 | In other words, return a copy of the initial segment of length N of | ||
29 | STRING. */ | ||
30 | char * | ||
31 | xstrndup (const char *string, size_t n) | ||
32 | { | ||
33 | char *s = strndup (string, n); | ||
34 | if (! s) | ||
35 | xalloc_die (); | ||
36 | return s; | ||
37 | } | ||
diff --git a/gl/xstrndup.h b/gl/xstrndup.h new file mode 100644 index 00000000..88354cfd --- /dev/null +++ b/gl/xstrndup.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* Duplicate a bounded initial segment of a string, with out-of-memory | ||
2 | checking. | ||
3 | Copyright (C) 2003 Free Software Foundation, Inc. | ||
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, or (at your option) | ||
8 | 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, write to the Free Software Foundation, | ||
17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
18 | |||
19 | #include <stddef.h> | ||
20 | |||
21 | /* Return a newly allocated copy of at most N bytes of STRING. | ||
22 | In other words, return a copy of the initial segment of length N of | ||
23 | STRING. */ | ||
24 | extern char *xstrndup (const char *string, size_t n); | ||