diff options
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); | ||
