summaryrefslogtreecommitdiffstats
path: root/gnu/lib
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/lib')
-rw-r--r--gnu/lib/Makefile18
-rw-r--r--gnu/lib/Makefile.inc3
-rw-r--r--gnu/lib/csu/Makefile80
-rw-r--r--gnu/lib/libdialog/Makefile20
-rw-r--r--gnu/lib/libdialog/dlg_config.h91
-rw-r--r--gnu/lib/libgcc/Makefile374
-rw-r--r--gnu/lib/libgcov/Makefile60
-rw-r--r--gnu/lib/libgomp/Makefile61
-rw-r--r--gnu/lib/libgomp/config.h109
-rw-r--r--gnu/lib/libobjc/Makefile50
-rw-r--r--gnu/lib/libodialog/CHANGES9
-rw-r--r--gnu/lib/libodialog/COPYING339
-rw-r--r--gnu/lib/libodialog/Makefile24
-rw-r--r--gnu/lib/libodialog/README8
-rw-r--r--gnu/lib/libodialog/TESTS/Makefile20
-rw-r--r--gnu/lib/libodialog/TESTS/check1.c83
-rw-r--r--gnu/lib/libodialog/TESTS/check2.c105
-rw-r--r--gnu/lib/libodialog/TESTS/check3.c92
-rw-r--r--gnu/lib/libodialog/TESTS/dselect.c41
-rw-r--r--gnu/lib/libodialog/TESTS/fselect.c44
-rw-r--r--gnu/lib/libodialog/TESTS/ftree1.c45
-rw-r--r--gnu/lib/libodialog/TESTS/ftree1.test73
-rw-r--r--gnu/lib/libodialog/TESTS/ftree2.c47
-rw-r--r--gnu/lib/libodialog/TESTS/ftree2.test73
-rw-r--r--gnu/lib/libodialog/TESTS/gauge.c41
-rw-r--r--gnu/lib/libodialog/TESTS/input1.c45
-rw-r--r--gnu/lib/libodialog/TESTS/input2.c47
-rw-r--r--gnu/lib/libodialog/TESTS/menu1.c96
-rw-r--r--gnu/lib/libodialog/TESTS/menu2.c96
-rw-r--r--gnu/lib/libodialog/TESTS/menu3.c107
-rw-r--r--gnu/lib/libodialog/TESTS/msg.c42
-rw-r--r--gnu/lib/libodialog/TESTS/prgbox.c41
-rw-r--r--gnu/lib/libodialog/TESTS/radio1.c71
-rw-r--r--gnu/lib/libodialog/TESTS/radio2.c89
-rw-r--r--gnu/lib/libodialog/TESTS/radio3.c98
-rw-r--r--gnu/lib/libodialog/TESTS/text.c41
-rw-r--r--gnu/lib/libodialog/TESTS/tree.c111
-rw-r--r--gnu/lib/libodialog/TESTS/yesno.c45
-rw-r--r--gnu/lib/libodialog/TODO36
-rw-r--r--gnu/lib/libodialog/checklist.c661
-rw-r--r--gnu/lib/libodialog/colors.h219
-rw-r--r--gnu/lib/libodialog/dialog.3842
-rw-r--r--gnu/lib/libodialog/dialog.h211
-rw-r--r--gnu/lib/libodialog/dialog.priv.h183
-rw-r--r--gnu/lib/libodialog/dir.c549
-rw-r--r--gnu/lib/libodialog/dir.h38
-rw-r--r--gnu/lib/libodialog/fselect.c402
-rw-r--r--gnu/lib/libodialog/gauge.c79
-rw-r--r--gnu/lib/libodialog/help.c194
-rw-r--r--gnu/lib/libodialog/inputbox.c190
-rw-r--r--gnu/lib/libodialog/kernel.c536
-rw-r--r--gnu/lib/libodialog/lineedit.c213
-rw-r--r--gnu/lib/libodialog/menubox.c469
-rw-r--r--gnu/lib/libodialog/msgbox.c346
-rw-r--r--gnu/lib/libodialog/notify.c53
-rw-r--r--gnu/lib/libodialog/prgbox.c152
-rw-r--r--gnu/lib/libodialog/radiolist.c628
-rw-r--r--gnu/lib/libodialog/raw_popen.c161
-rw-r--r--gnu/lib/libodialog/rc.c375
-rw-r--r--gnu/lib/libodialog/rc.h222
-rw-r--r--gnu/lib/libodialog/textbox.c699
-rw-r--r--gnu/lib/libodialog/tree.c1133
-rw-r--r--gnu/lib/libodialog/ui_objects.c829
-rw-r--r--gnu/lib/libodialog/ui_objects.h114
-rw-r--r--gnu/lib/libodialog/yesno.c169
-rw-r--r--gnu/lib/libreadline/Makefile5
-rw-r--r--gnu/lib/libreadline/Makefile.inc14
-rw-r--r--gnu/lib/libreadline/config.h270
-rw-r--r--gnu/lib/libreadline/history/Makefile15
-rw-r--r--gnu/lib/libreadline/history/doc/Makefile12
-rw-r--r--gnu/lib/libreadline/readline/Makefile27
-rw-r--r--gnu/lib/libreadline/readline/doc/Makefile20
-rw-r--r--gnu/lib/libregex/FREEBSD-upgrade18
-rw-r--r--gnu/lib/libregex/Makefile28
-rw-r--r--gnu/lib/libregex/config.h12
-rw-r--r--gnu/lib/libregex/doc/Makefile14
-rw-r--r--gnu/lib/libregex/doc/include.awk19
-rw-r--r--gnu/lib/libregex/doc/xregex.texi3021
-rw-r--r--gnu/lib/libregex/gnuregex.h33
-rw-r--r--gnu/lib/libregex/posix/regex.h593
-rw-r--r--gnu/lib/libregex/regcomp.c3924
-rw-r--r--gnu/lib/libregex/regex.c98
-rw-r--r--gnu/lib/libregex/regex.h47
-rw-r--r--gnu/lib/libregex/regex_internal.c1674
-rw-r--r--gnu/lib/libregex/regex_internal.h798
-rw-r--r--gnu/lib/libregex/regexec.c4327
-rw-r--r--gnu/lib/libssp/Makefile38
-rw-r--r--gnu/lib/libssp/config.h87
-rw-r--r--gnu/lib/libssp/libssp_nonshared/Makefile18
-rw-r--r--gnu/lib/libstdc++/Makefile627
-rw-r--r--gnu/lib/libstdc++/config.h1103
-rw-r--r--gnu/lib/libstdc++/doc/Makefile13
-rw-r--r--gnu/lib/libsupc++/Makefile39
93 files changed, 29436 insertions, 0 deletions
diff --git a/gnu/lib/Makefile b/gnu/lib/Makefile
new file mode 100644
index 0000000..cae52c3
--- /dev/null
+++ b/gnu/lib/Makefile
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+SUBDIR= csu libgcc libgcov libdialog libgomp libodialog libregex libreadline \
+ libssp
+
+# libsupc++ uses libstdc++ headers, although 'make includes' should
+# have taken care of that already.
+.if ${MK_CXX} != "no"
+SUBDIR+= libstdc++ libsupc++
+.endif
+
+.if ${MK_OBJC} != "no"
+SUBDIR+= libobjc
+.endif
+
+.include <bsd.subdir.mk>
diff --git a/gnu/lib/Makefile.inc b/gnu/lib/Makefile.inc
new file mode 100644
index 0000000..265f86d
--- /dev/null
+++ b/gnu/lib/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include "../Makefile.inc"
diff --git a/gnu/lib/csu/Makefile b/gnu/lib/csu/Makefile
new file mode 100644
index 0000000..4999d06
--- /dev/null
+++ b/gnu/lib/csu/Makefile
@@ -0,0 +1,80 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+MK_SSP= no
+
+GCCDIR= ${.CURDIR}/../../../contrib/gcc
+GCCLIB= ${.CURDIR}/../../../contrib/gcclibs
+CCDIR= ${.CURDIR}/../../usr.bin/cc
+.include "${CCDIR}/Makefile.tgt"
+
+.PATH: ${GCCDIR}/config/${GCC_CPU} ${GCCDIR}
+
+SRCS= crtstuff.c tconfig.h tm.h options.h
+OBJS= crtbegin.o crtend.o crtbeginT.o
+SOBJS= crtbegin.So crtend.So
+CSTD?= gnu89
+CFLAGS+= -DIN_GCC -DHAVE_LD_EH_FRAME_HDR -DDT_CONFIG -D__GLIBC__=3
+CFLAGS+= -finhibit-size-directive -fno-inline-functions \
+ -fno-exceptions -fno-zero-initialized-in-bss \
+ -fno-zero-initialized-in-bss -fno-toplevel-reorder \
+ -fno-asynchronous-unwind-tables -fno-omit-frame-pointer
+CFLAGS+= -I${GCCLIB}/include -I${GCCDIR}/config -I${GCCDIR} -I. \
+ -I${CCDIR}/cc_tools
+CRTS_CFLAGS= -DCRTSTUFFS_O -DSHARED ${PICFLAG}
+MKDEP= -DCRT_BEGIN
+
+.if ${MACHINE_CPUARCH} == "ia64"
+BEGINSRC= crtbegin.asm
+ENDSRC= crtend.asm
+CFLAGS+= -x assembler-with-cpp # Ugly hack
+CFLAGS+= -include osreldate.h
+.undef SRCS # hack for 'make depend'
+.endif
+.if ${MACHINE_CPUARCH} == "powerpc"
+TGTOBJS= crtsavres.o
+SRCS+= crtsavres.asm
+.endif
+.if ${MACHINE_CPUARCH} == "sparc64"
+TGTOBJS= crtfastmath.o
+SRCS+= crtfastmath.c
+.endif
+BEGINSRC?= crtstuff.c
+ENDSRC?= crtstuff.c
+
+all: ${OBJS} ${SOBJS} ${TGTOBJS}
+${OBJS} ${SOBJS}: ${SRCS:M*.h}
+
+CLEANFILES= ${OBJS} ${SOBJS} ${TGTOBJS}
+
+crtbegin.o: ${BEGINSRC}
+ ${CC} ${CFLAGS} -g0 -DCRT_BEGIN \
+ -c -o ${.TARGET} ${.ALLSRC:N*.h}
+
+crtbeginT.o: ${BEGINSRC}
+ ${CC} ${CFLAGS} -g0 -DCRT_BEGIN -DCRTSTUFFT_O \
+ -c -o ${.TARGET} ${.ALLSRC:N*.h}
+
+crtbegin.So: ${BEGINSRC}
+ ${CC} ${CFLAGS} -g0 -DCRT_BEGIN ${CRTS_CFLAGS} \
+ -c -o ${.TARGET} ${.ALLSRC:N*.h}
+
+crtend.o: ${ENDSRC}
+ ${CC} ${CFLAGS} -g0 -DCRT_END \
+ -c -o ${.TARGET} ${.ALLSRC:N*.h}
+
+crtend.So: ${ENDSRC}
+ ${CC} ${CFLAGS} -g0 -DCRT_END ${CRTS_CFLAGS} \
+ -c -o ${.TARGET} ${.ALLSRC:N*.h}
+
+CLEANFILES+= tm.h tconfig.h options.h optionlist cs-tconfig.h cs-tm.h
+tm.h tconfig.h options.h: ${CCDIR}/cc_tools/Makefile
+ ${MAKE} -f ${.ALLSRC} MFILE=${.ALLSRC} GCCDIR=${GCCDIR} ${.TARGET}
+
+realinstall:
+.for file in ${OBJS} ${SOBJS} ${TGTOBJS}
+ ${INSTALL} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${file} ${DESTDIR}${LIBDIR}/${file:S/.So$/S.o/}
+.endfor
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libdialog/Makefile b/gnu/lib/libdialog/Makefile
new file mode 100644
index 0000000..7547a60
--- /dev/null
+++ b/gnu/lib/libdialog/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+DIALOG= ${.CURDIR}/../../../contrib/dialog
+
+LIB= dialog
+SHLIB_MAJOR= 7
+SRCS= argv.c arrows.c buttons.c calendar.c checklist.c columns.c \
+ dlg_keys.c editbox.c fselect.c formbox.c guage.c inputbox.c \
+ inputstr.c menubox.c mixedform.c mixedgauge.c mouse.c \
+ mousewget.c msgbox.c pause.c prgbox.c progressbox.c rc.c \
+ tailbox.c textbox.c timebox.c trace.c ui_getc.c util.c \
+ version.c yesno.c
+INCS= dialog.h dlg_colors.h dlg_config.h dlg_keys.h
+MAN= dialog.3
+
+CFLAGS+= -I${.CURDIR} -I${DIALOG} -D_XOPEN_SOURCE_EXTENDED
+.PATH: ${DIALOG}
+WARNS?= 3
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libdialog/dlg_config.h b/gnu/lib/libdialog/dlg_config.h
new file mode 100644
index 0000000..4dd6ab4
--- /dev/null
+++ b/gnu/lib/libdialog/dlg_config.h
@@ -0,0 +1,91 @@
+/* dlg_config.h. Generated automatically by configure. */
+/*
+ * The configure script expands this as a set of definitions
+ *
+ * $FreeBSD$
+ */
+
+#define DIALOG_PATCHDATE 20100428
+#define DIALOG_VERSION "1.1"
+#define HAVE_ALLOCA 1
+#define HAVE_COLOR 1
+#define HAVE_DIRENT_H 1
+#define HAVE_DLG_FORMBOX 1
+#define HAVE_DLG_GAUGE 1
+#define HAVE_DLG_MIXEDFORM 1
+#define HAVE_DLG_TAILBOX 1
+#define HAVE_DLG_TRACE 1
+#define HAVE_FEOF_UNLOCKED 1
+#define HAVE_FLUSHINP 1
+#define HAVE_FSEEKO 1
+#define HAVE_GETBEGX 1
+#define HAVE_GETBEGY 1
+#define HAVE_GETBEGYX 1
+#define HAVE_GETCURX 1
+#define HAVE_GETCURY 1
+#define HAVE_GETCWD 1
+#define HAVE_GETEGID 1
+#define HAVE_GETEUID 1
+#define HAVE_GETGID 1
+#define HAVE_GETMAXX 1
+#define HAVE_GETMAXY 1
+#define HAVE_GETMAXYX 1
+#define HAVE_GETPAGESIZE 1
+#define HAVE_GETPARX 1
+#define HAVE_GETPARY 1
+#define HAVE_GETPARYX 1
+#define HAVE_GETUID 1
+#define HAVE_ICONV 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_LANGINFO_CODESET 1
+#define HAVE_LC_MESSAGES 1
+#define HAVE_LIBNCURSESW 1
+#define HAVE_LIMITS_H 1
+#define HAVE_LOCALE_H 1
+#define HAVE_MBSTATE_T 1
+#define HAVE_MEMORY_H 1
+#define HAVE_MIXEDGAUGE 1
+#define HAVE_MMAP 1
+#define HAVE_MUNMAP 1
+#define HAVE_NL_TYPES_H 1
+#define HAVE_PUTENV 1
+#define HAVE_RC_FILE 1
+#define HAVE_SEARCH_H 1
+#define HAVE_SETENV 1
+#define HAVE_SETLOCALE 1
+#define HAVE_STDDEF_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STPCPY 1
+#define HAVE_STRCASECMP 1
+#define HAVE_STRCHR 1
+#define HAVE_STRDUP 1
+#define HAVE_STRFTIME 1
+#define HAVE_STRINGS_H 1
+#define HAVE_STRING_H 1
+#define HAVE_STRTOUL 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_WAIT_H 1
+#define HAVE_TERM_H 1
+#define HAVE_TSEARCH 1
+#define HAVE_TYPE_CHTYPE 1
+#define HAVE_UNCTRL_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_USE_DEFAULT_COLORS 1
+#define HAVE_WAITPID 1
+#define HAVE_WGET_WCH 1
+#define HAVE_XDIALOG 1
+#define HAVE__NC_FREE_AND_EXIT 1
+#define ICONV_CONST const
+#define MIXEDCASE_FILENAMES 1
+#define NCURSES 1
+#define NEED_WCHAR_H 1
+#define PACKAGE "dialog"
+#define RETSIGTYPE void
+#define STDC_HEADERS 1
+#define SYSTEM_NAME "freebsd9.0"
+#define TIME_WITH_SYS_TIME 1
+#define TYPE_CHTYPE_IS_SCALAR 1
+#define USE_WIDE_CURSES 1
diff --git a/gnu/lib/libgcc/Makefile b/gnu/lib/libgcc/Makefile
new file mode 100644
index 0000000..7f6fc0d
--- /dev/null
+++ b/gnu/lib/libgcc/Makefile
@@ -0,0 +1,374 @@
+# $FreeBSD$
+
+GCCDIR= ${.CURDIR}/../../../contrib/gcc
+GCCLIB= ${.CURDIR}/../../../contrib/gcclibs
+
+SHLIB_NAME= libgcc_s.so.1
+SHLIBDIR?= /lib
+
+.include <bsd.own.mk>
+#
+# libgcc is linked in last and thus cannot depend on ssp symbols coming
+# from earlier libraries. Disable stack protection for this library.
+#
+MK_SSP= no
+
+.include "${.CURDIR}/../../usr.bin/cc/Makefile.tgt"
+
+.if ${TARGET_CPUARCH} == "sparc64" || ${TARGET_CPUARCH} == "mips"
+LIB= gcc
+.endif
+
+.PATH: ${GCCDIR}/config/${GCC_CPU} ${GCCDIR}/config ${GCCDIR}
+
+CFLAGS+= -DIN_GCC -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED \
+ -DHAVE_GTHR_DEFAULT \
+ -I${GCCLIB}/include \
+ -I${GCCDIR}/config -I${GCCDIR} -I. \
+ -I${.CURDIR}/../../usr.bin/cc/cc_tools
+
+LDFLAGS+= -nodefaultlibs
+LDADD+= -lc
+
+OBJS= # added to below in various ways depending on TARGET_CPUARCH
+
+#---------------------------------------------------------------------------
+#
+# When upgrading GCC, get the following defintions straight from Makefile.in
+#
+# Library members defined in libgcc2.c.
+LIB2FUNCS= _muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3 \
+ _cmpdi2 _ucmpdi2 _clear_cache \
+ _enable_execute_stack _trampoline __main _absvsi2 _absvdi2 _addvsi3 \
+ _addvdi3 _subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors \
+ _ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab \
+ _popcountsi2 _popcountdi2 _paritysi2 _paritydi2 _powisf2 _powidf2 \
+ _powixf2 _powitf2 _mulsc3 _muldc3 _mulxc3 _multc3 _divsc3 _divdc3 \
+ _divxc3 _divtc3
+
+# The floating-point conversion routines that involve a single-word integer.
+.for mode in sf df xf
+LIB2FUNCS+= _fixuns${mode}si
+.endfor
+
+# Likewise double-word routines.
+.for mode in sf df xf tf
+LIB2FUNCS+= _fix${mode}di _fixuns${mode}di
+LIB2FUNCS+= _floatdi${mode} _floatundi${mode}
+.endfor
+
+LIB2ADD = $(LIB2FUNCS_EXTRA)
+LIB2ADD_ST = $(LIB2FUNCS_STATIC_EXTRA)
+
+# Additional sources to handle exceptions; overridden by targets as needed.
+LIB2ADDEH = unwind-dw2.c unwind-dw2-fde-glibc.c unwind-sjlj.c gthr-gnat.c \
+ unwind-c.c
+LIB2ADDEHSTATIC = $(LIB2ADDEH)
+LIB2ADDEHSHARED = $(LIB2ADDEH)
+
+# List of extra C and assembler files to add to static and shared libgcc2.
+# Assembler files should have names ending in `.asm'.
+LIB2FUNCS_EXTRA =
+
+# List of extra C and assembler files to add to static libgcc2.
+# Assembler files should have names ending in `.asm'.
+LIB2FUNCS_STATIC_EXTRA =
+
+# Defined in libgcc2.c, included only in the static library.
+# KAN: Excluded _sf_to_tf and _df_to_tf as TPBIT_FUNCS are not
+# built on any of our platforms.
+LIB2FUNCS_ST = _eprintf __gcc_bcmp
+
+FPBIT_FUNCS = _pack_sf _unpack_sf _addsub_sf _mul_sf _div_sf \
+ _fpcmp_parts_sf _compare_sf _eq_sf _ne_sf _gt_sf _ge_sf \
+ _lt_sf _le_sf _unord_sf _si_to_sf _sf_to_si _negate_sf _make_sf \
+ _sf_to_df _thenan_sf _sf_to_usi _usi_to_sf
+
+DPBIT_FUNCS = _pack_df _unpack_df _addsub_df _mul_df _div_df \
+ _fpcmp_parts_df _compare_df _eq_df _ne_df _gt_df _ge_df \
+ _lt_df _le_df _unord_df _si_to_df _df_to_si _negate_df _make_df \
+ _df_to_sf _thenan_df _df_to_usi _usi_to_df
+
+TPBIT_FUNCS = _pack_tf _unpack_tf _addsub_tf _mul_tf _div_tf \
+ _fpcmp_parts_tf _compare_tf _eq_tf _ne_tf _gt_tf _ge_tf \
+ _lt_tf _le_tf _unord_tf _si_to_tf _tf_to_si _negate_tf _make_tf \
+ _tf_to_df _tf_to_sf _thenan_tf _tf_to_usi _usi_to_tf
+
+# These might cause a divide overflow trap and so are compiled with
+# unwinder info.
+LIB2_DIVMOD_FUNCS = _divdi3 _moddi3 _udivdi3 _umoddi3 _udiv_w_sdiv _udivmoddi4
+
+#-----------------------------------------------------------------------
+#
+# Platform specific bits.
+# When upgrading GCC, get the following definitions from config/<cpu>/t-*
+#
+.if ${TARGET_CPUARCH} == "arm"
+# from config/arm/t-strongarm-elf
+CFLAGS+= -Dinhibit_libc -fno-inline
+LIB1ASMSRC = lib1funcs.asm
+LIB1ASMFUNCS = _dvmd_tls _bb_init_func
+LIB2FUNCS_EXTRA = floatunsidf.c floatunsisf.c
+
+# Not now
+#LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _bb_init_func
+#LIB1ASMFUNCS+= _call_via_rX _interwork_call_via_rX \
+# _lshrdi3 _ashrdi3 _ashldi3 \
+# _negdf2 _addsubdf3 _muldivdf3 _cmpdf2 _unorddf2 _fixdfsi _fixunsdfsi \
+# _truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \
+# _fixsfsi _fixunssfsi _floatdidf _floatdisf
+.endif
+
+.if ${TARGET_CPUARCH} == mips
+LIB2FUNCS_EXTRA = floatunsidf.c floatunsisf.c
+# ABIs other than o32 need this
+.if ${TARGET_ARCH:Mmipse[lb]} == ""
+LIB2FUNCS_EXTRA+= floatdidf.c fixunsdfsi.c
+LIB2FUNCS_EXTRA+= floatdisf.c floatundidf.c
+LIB2FUNCS_EXTRA+= fixsfdi.c floatundisf.c
+LIB2FUNCS_EXTRA+= fixdfdi.c fixunssfsi.c
+.endif
+.endif
+
+.if ${TARGET_CPUARCH} == "ia64"
+# from config/ia64/t-ia64
+LIB1ASMSRC = lib1funcs.asm
+LIB1ASMFUNCS = __divxf3 __divdf3 __divsf3 \
+ __divdi3 __moddi3 __udivdi3 __umoddi3 \
+ __divsi3 __modsi3 __udivsi3 __umodsi3 __save_stack_nonlocal \
+ __nonlocal_goto __restore_stack_nonlocal __trampoline \
+ _fixtfdi _fixunstfdi _floatditf
+LIB2ADDEH = unwind-ia64.c unwind-sjlj.c unwind-c.c
+.endif
+
+.if ${TARGET_ARCH} == "powerpc"
+# from config/rs6000/t-ppccomm
+LIB2FUNCS_EXTRA = tramp.asm
+LIB2FUNCS_STATIC_EXTRA = eabi.asm
+.endif
+
+.if ${TARGET_ARCH} == "powerpc64"
+# from config/rs6000/t-ppccomm
+LIB2FUNCS_EXTRA = tramp.asm
+.endif
+
+.if ${TARGET_CPUARCH} == "sparc64"
+# from config/sparc/t-elf
+LIB1ASMSRC = lb1spc.asm
+LIB1ASMFUNCS = _mulsi3 _divsi3 _modsi3
+.endif
+
+#-----------------------------------------------------------------------
+
+# Remove any objects from LIB2FUNCS and LIB2_DIVMOD_FUNCS that are
+# defined as optimized assembly code in LIB1ASMFUNCS.
+.if defined(LIB1ASMFUNCS)
+.for sym in ${LIB1ASMFUNCS}
+LIB2FUNCS:= ${LIB2FUNCS:S/${sym}//g}
+LIB2_DIVMOD_FUNCS:= ${LIB2_DIVMOD_FUNCS:S/${sym}//g}
+.endfor
+.endif
+
+COMMONHDRS= tm.h tconfig.h options.h unwind.h gthr-default.h
+
+#-----------------------------------------------------------------------
+#
+# Helpful shortcuts for compiler invocations.
+#
+HIDE = -fvisibility=hidden -DHIDE_EXPORTS
+CC_T = ${CC} -c ${CFLAGS} ${HIDE} -fPIC
+CC_P = ${CC} -c ${CFLAGS} ${HIDE} -p -fPIC
+CC_S = ${CC} -c ${CFLAGS} ${PICFLAG} -DSHARED
+
+#-----------------------------------------------------------------------
+#
+# Functions from libgcc2.c
+#
+STD_CFLAGS =
+DIV_CFLAGS = -fexceptions -fnon-call-exceptions
+
+STD_FUNCS = ${LIB2FUNCS}
+DIV_FUNCS = ${LIB2_DIVMOD_FUNCS}
+
+STD_CFILE = libgcc2.c
+DIV_CFILE = libgcc2.c
+
+OBJ_GRPS = STD DIV
+
+#-----------------------------------------------------------------------
+#
+# Floating point emulation functions
+#
+.if ${TARGET_CPUARCH} == "armNOT_YET" || \
+ ${TARGET_CPUARCH} == "powerpc" || ${TARGET_CPUARCH} == "sparc64"
+
+FPBIT_CFLAGS = -DFINE_GRAINED_LIBRARIES -DFLOAT
+DPBIT_CFLAGS = -DFINE_GRAINED_LIBRARIES
+
+FPBIT_CFILE = config/fp-bit.c
+DPBIT_CFILE = config/fp-bit.c
+
+OBJ_GRPS += FPBIT DPBIT
+.endif
+
+#-----------------------------------------------------------------------
+#
+# Generic build rules for object groups defined above
+#
+.for T in ${OBJ_GRPS}
+${T}_OBJS_T = ${${T}_FUNCS:S/$/.o/}
+${T}_OBJS_P = ${${T}_FUNCS:S/$/.po/}
+${T}_OBJS_S = ${${T}_FUNCS:S/$/.So/}
+OBJS += ${${T}_FUNCS:S/$/.o/}
+
+${${T}_OBJS_T}: ${${T}_CFILE} ${COMMONHDRS}
+ ${CC_T} ${${T}_CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.ALLSRC:M*.c}
+${${T}_OBJS_P}: ${${T}_CFILE} ${COMMONHDRS}
+ ${CC_P} ${${T}_CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.ALLSRC:M*.c}
+${${T}_OBJS_S}: ${${T}_CFILE} ${COMMONHDRS}
+ ${CC_S} ${${T}_CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.ALLSRC:M*.c}
+.endfor
+
+#-----------------------------------------------------------------------
+#
+# Extra objects coming from separate files
+#
+.if !empty(LIB2ADD)
+OBJS += ${LIB2ADD:R:S/$/.o/}
+SOBJS += ${LIB2ADD:R:S/$/.So/}
+POBJS += ${LIB2ADD:R:S/$/.po/}
+.endif
+
+#-----------------------------------------------------------------------
+#
+# Objects that should be in static library only.
+#
+SYMS_ST = ${LIB2FUNCS_ST} ${LIB2ADD_ST}
+STAT_OBJS_T = ${SYMS_ST:S/$/.o/}
+STAT_OBJS_P = ${SYMS_ST:S/$/.po/}
+STATICOBJS = ${SYMS_ST:S/$/.o/}
+
+${STAT_OBJS_T}: ${STD_CFILE} ${COMMONHDRS}
+ ${CC_T} -DL${.PREFIX} -o ${.TARGET} ${.ALLSRC:M*.c}
+${STAT_OBJS_P}: ${STD_CFILE} ${COMMONHDRS}
+ ${CC_P} -DL${.PREFIX} -o ${.TARGET} ${.ALLSRC:M*.c}
+
+#-----------------------------------------------------------------------
+#
+# Assembler files.
+#
+.if defined(LIB1ASMSRC)
+ASM_T = ${LIB1ASMFUNCS:S/$/.o/}
+ASM_P = ${LIB1ASMFUNCS:S/$/.po/}
+ASM_S = ${LIB1ASMFUNCS:S/$/.So/}
+ASM_V = ${LIB1ASMFUNCS:S/$/.vis/}
+OBJS += ${LIB1ASMFUNCS:S/$/.o/}
+
+${ASM_T}: ${LIB1ASMSRC} ${.PREFIX}.vis
+ ${CC} -x assembler-with-cpp -c ${CFLAGS} -DL${.PREFIX} \
+ -o ${.TARGET} -include ${.PREFIX}.vis ${.ALLSRC:N*.h:N*.vis}
+${ASM_P}: ${LIB1ASMSRC} ${.PREFIX}.vis
+ ${CC} -x assembler-with-cpp -p -c ${CFLAGS} -DL${.PREFIX} \
+ -o ${.TARGET} -include ${.PREFIX}.vis ${.ALLSRC:N*.h:N*.vis}
+${ASM_S}: ${LIB1ASMSRC}
+ ${CC} -x assembler-with-cpp -c ${PICFLAG} ${CFLAGS} -DL${.PREFIX} \
+ -o ${.TARGET} ${.ALLSRC:N*.h}
+${ASM_V}: ${LIB1ASMSRC}
+ ${CC} -x assembler-with-cpp -c ${CFLAGS} -DL${.PREFIX} \
+ -o ${.PREFIX}.vo ${.ALLSRC:N*.h}
+ ( nm -pg ${.PREFIX}.vo | \
+ awk 'NF == 3 && $$2 !~ /^[UN]$$/ { print "\t.hidden ", $$3 }'\
+ ) > ${.TARGET}
+
+CLEANFILES += ${ASM_V} ${ASM_V:R:S/$/.vo/}
+.endif
+
+#-----------------------------------------------------------------------
+#
+# Exception handling / unwinding support.
+#
+EH_OBJS_T = ${LIB2ADDEHSTATIC:R:S/$/.o/}
+EH_OBJS_P = ${LIB2ADDEHSTATIC:R:S/$/.po/}
+EH_OBJS_S = ${LIB2ADDEHSHARED:R:S/$/.So/}
+EH_CFLAGS = -fexceptions -D__GLIBC__=3 -DElfW=__ElfN
+SOBJS += ${EH_OBJS_S}
+
+.for _src in ${LIB2ADDEHSTATIC}
+${_src:R:S/$/.o/}: ${_src} ${COMMONHDRS}
+ ${CC_T} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
+${_src:R:S/$/.po/}: ${_src} ${COMMONHDRS}
+ ${CC_P} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
+.endfor
+.for _src in ${LIB2ADDEHSHARED}
+${_src:R:S/$/.So/}: ${_src} ${COMMONHDRS}
+ ${CC_S} ${EH_CFLAGS} -o ${.TARGET} ${.IMPSRC}
+.endfor
+
+
+#-----------------------------------------------------------------------
+#
+# Generated headers
+#
+${COMMONHDRS}: ${.CURDIR}/../../usr.bin/cc/cc_tools/Makefile
+ ${MAKE} -f ${.ALLSRC} MFILE=${.ALLSRC} GCCDIR=${GCCDIR} ${.TARGET}
+
+CLEANFILES += ${COMMONHDRS}
+CLEANFILES += cs-*.h option*
+
+#-----------------------------------------------------------------------
+#
+# Build symbol version map
+#
+SHLIB_MKMAP = ${GCCDIR}/mkmap-symver.awk
+SHLIB_MKMAP_OPTS =
+SHLIB_MAPFILES = ${GCCDIR}/libgcc-std.ver
+VERSION_MAP = libgcc.map
+
+libgcc.map: ${SHLIB_MKMAP} ${SHLIB_MAPFILES} ${SOBJS} ${OBJS:R:S/$/.So/}
+ ( nm -pg ${SOBJS};echo %% ; \
+ cat ${SHLIB_MAPFILES} \
+ | sed -e '/^[ ]*#/d' \
+ -e 's/^%\(if\|else\|elif\|endif\|define\)/#\1/' \
+ | ${CC} ${CFLAGS} -E -xassembler-with-cpp -; \
+ ) | awk -f ${SHLIB_MKMAP} ${SHLIB_MKMAP_OPTS} > ${.TARGET}
+
+CLEANFILES += libgcc.map
+
+#-----------------------------------------------------------------------
+#
+# Build additional static libgcc_eh[_p].a libraries.
+#
+libgcc_eh.a: ${EH_OBJS_T}
+ @${ECHO} building static gcc_eh library
+ @rm -f ${.TARGET}
+ @${AR} cq ${.TARGET} `lorder ${EH_OBJS_T} | tsort -q`
+ ${RANLIB} ${.TARGET}
+
+all: libgcc_eh.a
+
+.if ${MK_PROFILE} != "no"
+libgcc_eh_p.a: ${EH_OBJS_P}
+ @${ECHO} building profiled gcc_eh library
+ @rm -f ${.TARGET}
+ @${AR} cq ${.TARGET} `lorder ${EH_OBJS_P} | tsort -q`
+ ${RANLIB} ${.TARGET}
+all: libgcc_eh_p.a
+.endif
+
+_libinstall: _lib-eh-install
+
+_lib-eh-install:
+.if ${MK_INSTALLLIB} != "no"
+ ${INSTALL} -C -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${_INSTALLFLAGS} libgcc_eh.a ${DESTDIR}${LIBDIR}
+.endif
+.if ${MK_PROFILE} != "no"
+ ${INSTALL} -C -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${_INSTALLFLAGS} libgcc_eh_p.a ${DESTDIR}${LIBDIR}
+.endif
+
+CLEANFILES+= libgcc_eh.a libgcc_eh_p.a ${EH_OBJS_T} ${EH_OBJS_P}
+
+.include <bsd.lib.mk>
+
+.SUFFIXES: .vis .vo
diff --git a/gnu/lib/libgcov/Makefile b/gnu/lib/libgcov/Makefile
new file mode 100644
index 0000000..680cdbf
--- /dev/null
+++ b/gnu/lib/libgcov/Makefile
@@ -0,0 +1,60 @@
+# $FreeBSD$
+
+NO_PROFILE=
+.include <bsd.own.mk>
+MK_SSP= no
+.include "${.CURDIR}/../../usr.bin/cc/Makefile.tgt"
+
+GCCDIR= ${.CURDIR}/../../../contrib/gcc
+GCCLIB= ${.CURDIR}/../../../contrib/gcclibs
+.PATH: ${GCCDIR}/config/${GCC_CPU} ${GCCDIR}
+
+LIB= gcov
+
+CFLAGS+= -DIN_GCC -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED
+CFLAGS+= -D_PTHREADS -DGTHREAD_USE_WEAK
+CFLAGS+= -I${.CURDIR}/../../usr.bin/cc/cc_tools \
+ -I${GCCLIB}/include -I${GCCDIR}/config -I${GCCDIR} -I.
+#
+# Library members defined in libgcov.c.
+# Defined in libgcov.c, included only in gcov library
+SYMS = _gcov _gcov_merge_add _gcov_merge_single _gcov_merge_delta \
+ _gcov_fork _gcov_execl _gcov_execlp _gcov_execle \
+ _gcov_execv _gcov_execvp _gcov_execve \
+ _gcov_interval_profiler _gcov_pow2_profiler _gcov_one_value_profiler
+
+OBJS= ${SYMS:S/$/.o/}
+OBJS_T= ${SYMS:S/$/.o/}
+OBJS_P= ${SYMS:S/$/.po/}
+OBJS_S= ${SYMS:S/$/.So/}
+
+#-----------------------------------------------------------------------
+#
+# Helpful shortcuts for compiler invocations.
+#
+CC_T = ${CC} -c ${CFLAGS} -fPIC
+CC_P = ${CC} -c ${CFLAGS} -p -fPIC
+CC_S = ${CC} -c ${CFLAGS} ${PICFLAG} -DSHARED
+
+COMMONHDRS= tm.h tconfig.h gcov-iov.h options.h
+CLEANFILES+= ${COMMONHDRS} cs-tm.h cs-tconfig.h options.h optionlist
+
+${COMMONHDRS}: ${.CURDIR}/../../usr.bin/cc/cc_tools/Makefile
+ ${MAKE} -f ${.ALLSRC} MFILE=${.ALLSRC} GCCDIR=${GCCDIR} ${.TARGET}
+
+${OBJS} beforedepend: ${COMMONHDRS}
+
+${OBJS_T}: libgcov.c
+ ${CC_T} -DL${.PREFIX} -o ${.TARGET} ${.ALLSRC:M*.c}
+
+.if !defined(NO_PIC)
+${OBJS_S}: libgcov.c
+ ${CC_S} -DL${.PREFIX} -o ${.TARGET} ${.ALLSRC:M*.c}
+.endif
+
+.if ${MK_PROFILE} != "no"
+${OBJS_P}: libgcov.c
+ ${CC_P} -DL${.PREFIX} -o ${.TARGET} ${.ALLSRC:M*.c}
+.endif
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libgomp/Makefile b/gnu/lib/libgomp/Makefile
new file mode 100644
index 0000000..237c14a
--- /dev/null
+++ b/gnu/lib/libgomp/Makefile
@@ -0,0 +1,61 @@
+# $FreeBSD$
+
+GCCDIR= ${.CURDIR}/../../../contrib/gcc
+GCCLIB= ${.CURDIR}/../../../contrib/gcclibs
+SRCDIR= ${GCCLIB}/libgomp
+
+.PATH: ${SRCDIR} ${SRCDIR}/config/posix
+
+LIB= gomp
+SHLIB_MAJOR= 1
+
+SRCS= alloc.c barrier.c critical.c env.c \
+ error.c iter.c loop.c ordered.c parallel.c sections.c \
+ single.c team.c work.c lock.c mutex.c proc.c sem.c \
+ bar.c time.c fortran.c
+SRCS+= gstdint.h libgomp_f.h omp.h omp_lib.h
+
+INCS+= omp.h
+
+CFLAGS+= -DHAVE_CONFIG_H
+CFLAGS+= -I${.CURDIR} -I. -I${SRCDIR} -I${SRCDIR}/config/posix
+
+VERSION_MAP= ${SRCDIR}/libgomp.map
+
+# Target-specific OpenMP configuration
+.if ${MACHINE_CPUARCH} == arm || ${MACHINE_CPUARCH} == i386 || \
+ ${MACHINE_ARCH} == powerpc || \
+ (${MACHINE_CPUARCH} == mips && ${MACHINE_ARCH:Mmips64*} == "")
+OMP_LOCK_ALIGN = 4
+OMP_LOCK_KIND= 4
+OMP_LOCK_SIZE= 4
+OMP_NEST_LOCK_ALIGN= 4
+OMP_NEST_LOCK_KIND= 8
+OMP_NEST_LOCK_SIZE= 8
+.else
+OMP_LOCK_ALIGN = 8
+OMP_LOCK_KIND= 8
+OMP_LOCK_SIZE= 8
+OMP_NEST_LOCK_ALIGN= 8
+OMP_NEST_LOCK_KIND= 8
+OMP_NEST_LOCK_SIZE= 16
+.endif
+
+gstdint.h:
+ echo '#include <sys/types.h>' > ${.TARGET}
+ echo '#include <stdint.h>' >> ${.TARGET}
+CLEANFILES+= gstdint.h
+
+.for HFILE in libgomp_f.h omp.h omp_lib.h
+${HFILE}: ${SRCDIR}/${HFILE}.in ${.CURDIR}/Makefile
+ sed -e 's/@OMP_LOCK_ALIGN@/${OMP_LOCK_ALIGN}/g' \
+ -e 's/@OMP_LOCK_KIND@/${OMP_LOCK_KIND}/g' \
+ -e 's/@OMP_LOCK_SIZE@/${OMP_LOCK_SIZE}/g' \
+ -e 's/@OMP_NEST_LOCK_ALIGN@/${OMP_NEST_LOCK_ALIGN}/g' \
+ -e 's/@OMP_NEST_LOCK_KIND@/${OMP_NEST_LOCK_KIND}/g' \
+ -e 's/@OMP_NEST_LOCK_SIZE@/${OMP_NEST_LOCK_SIZE}/g' \
+ < ${SRCDIR}/${HFILE}.in > ${.TARGET}
+CLEANFILES+= ${HFILE}
+.endfor
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libgomp/config.h b/gnu/lib/libgomp/config.h
new file mode 100644
index 0000000..c56d860
--- /dev/null
+++ b/gnu/lib/libgomp/config.h
@@ -0,0 +1,109 @@
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+/* $FreeBSD$ */
+
+/* Define to 1 if the target supports __attribute__((alias(...))). */
+#define HAVE_ATTRIBUTE_ALIAS 1
+
+/* Define to 1 if the target supports __attribute__((dllexport)). */
+/* #undef HAVE_ATTRIBUTE_DLLEXPORT */
+
+/* Define to 1 if the target supports __attribute__((visibility(...))). */
+#define HAVE_ATTRIBUTE_VISIBILITY 1
+
+/* Define if the POSIX Semaphores do not work on your system. */
+/* #undef HAVE_BROKEN_POSIX_SEMAPHORES */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define to 1 if you have the `getloadavg' function. */
+#define HAVE_GETLOADAVG 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <semaphore.h> header file. */
+#define HAVE_SEMAPHORE_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if the target supports __sync_*_compare_and_swap */
+#ifdef __amd64__
+#define HAVE_SYNC_BUILTINS 1
+#endif
+
+/* Define to 1 if you have the <sys/loadavg.h> header file. */
+/* #undef HAVE_SYS_LOADAVG_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if the target supports thread-local storage. */
+#if !defined(__arm__) && !defined(__mips__)
+#define HAVE_TLS 1
+#endif
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Name of package */
+#define PACKAGE "libgomp"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "GNU OpenMP Runtime Library"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "GNU OpenMP Runtime Library 1.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libgomp"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.0"
+
+/* The size of a `char', as computed by sizeof. */
+/* #undef SIZEOF_CHAR */
+
+/* The size of a `int', as computed by sizeof. */
+/* #undef SIZEOF_INT */
+
+/* The size of a `long', as computed by sizeof. */
+/* #undef SIZEOF_LONG */
+
+/* The size of a `short', as computed by sizeof. */
+/* #undef SIZEOF_SHORT */
+
+/* The size of a `void *', as computed by sizeof. */
+/* #undef SIZEOF_VOID_P */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.0"
diff --git a/gnu/lib/libobjc/Makefile b/gnu/lib/libobjc/Makefile
new file mode 100644
index 0000000..80d0240
--- /dev/null
+++ b/gnu/lib/libobjc/Makefile
@@ -0,0 +1,50 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+OBJCDIR=${.CURDIR}/../../../contrib/libobjc
+GCCDIR= ${.CURDIR}/../../../contrib/gcc
+GCCLIB= ${.CURDIR}/../../../contrib/gcclibs
+
+.PATH: ${OBJCDIR}/objc ${OBJCDIR}
+
+LIB= objc
+SHLIB_MAJOR= 4
+
+SRCS= archive.c class.c encoding.c gc.c hash.c init.c linking.m misc.c \
+ nil_method.c NXConstStr.m Object.m objects.c Protocol.m sarray.c \
+ selector.c sendmsg.c thr.c thr-objc.c exception.c
+
+# XXX: clang cannot compile libobjc yet
+CC:=${CC:C/^(.*\/)?clang$/gcc/1}
+
+INCS= encoding.h hash.h objc-api.h objc-decls.h objc-list.h objc.h runtime.h \
+ sarray.h thr.h typedstream.h NXConstStr.h Object.h Protocol.h
+INCSDIR=${INCLUDEDIR}/objc
+
+CFLAGS+= -DHAVE_GTHR_DEFAULT -DIN_GCC -DIN_TARGET_LIBS
+CFLAGS+= -I. -I${.CURDIR}/../../usr.bin/cc/cc_tools
+CFLAGS+= -I${OBJCDIR}/objc -I${OBJCDIR}
+CFLAGS+= -I${GCCDIR}/config -I${GCCDIR}
+CFLAGS+= -I${GCCLIB}/include
+CFLAGS+= -fexceptions -frandom-seed=RepeatabilityConsideredGood
+OBJCFLAGS= -fgnu-runtime ${CFLAGS}
+
+GENHDRS= runtime-info.h
+
+runtime-info.h:
+ `${CC} --print-prog-name=cc1obj` -print-objc-runtime-info \
+ < /dev/null > ${.TARGET}
+
+.for H in tconfig.h tm.h config.h options.h gthr-default.h unwind.h
+$H: ${.CURDIR}/../../usr.bin/cc/cc_tools/Makefile
+ ${MAKE} -f ${.ALLSRC} MFILE=${.ALLSRC} GCCDIR=${GCCDIR} ${.TARGET}
+GENHDRS+= $H
+.endfor
+
+CLEANFILES+= ${GENHDRS} cs-* optionlist
+SRCS+= ${GENHDRS}
+
+${OBJS}: ${GENHDRS}
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libodialog/CHANGES b/gnu/lib/libodialog/CHANGES
new file mode 100644
index 0000000..1467a0e
--- /dev/null
+++ b/gnu/lib/libodialog/CHANGES
@@ -0,0 +1,9 @@
+- Added two variables to call to dialog_menu() to save the position
+ in the menu when choosing a menu-option.
+
+- Added dialog_fselect(), implements a fileselector dialog
+- Added ui-interface objects: Stringobject, Listobject and Buttonobject.
+ The fileselector dialog was built using these objects.
+- changed dialog_menu to use PGUP and PGDN
+- Added dialog_mesgbox, which display text given in a char buffer.
+-
diff --git a/gnu/lib/libodialog/COPYING b/gnu/lib/libodialog/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/gnu/lib/libodialog/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/gnu/lib/libodialog/Makefile b/gnu/lib/libodialog/Makefile
new file mode 100644
index 0000000..b03bb4a
--- /dev/null
+++ b/gnu/lib/libodialog/Makefile
@@ -0,0 +1,24 @@
+# Makefile for libdialog
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+LIB= odialog
+#MAN= NOMAN
+
+SHLIB_MAJOR= 7
+SRCS= kernel.c rc.c checklist.c inputbox.c menubox.c msgbox.c \
+ lineedit.c radiolist.c textbox.c yesno.c prgbox.c raw_popen.c \
+ fselect.c ui_objects.c dir.c notify.c help.c gauge.c tree.c
+
+CFLAGS+= -I${.CURDIR} -Wall -Wstrict-prototypes -DLOCALE
+
+DPADD= ${LIBNCURSES}
+LDADD= -lncurses
+
+.if ${MK_HTML} != "no"
+FILES= ${EXAMPLES:C;^;${.CURDIR}/TESTS/;}
+FILESDIR= ${SHAREDIR}/examples/libdialog
+.endif
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libodialog/README b/gnu/lib/libodialog/README
new file mode 100644
index 0000000..e5e6d56
--- /dev/null
+++ b/gnu/lib/libodialog/README
@@ -0,0 +1,8 @@
+This library was split out from the `dialog' program for use
+in C programs. For a list of interface functions, see dialog.h.
+For usage examples, see the `dialog' program sources in
+/usr/src/gnu/usr.bin/dialog.
+
+You can additionally use any ncurses functions after init_dialog().
+
+ Ache.
diff --git a/gnu/lib/libodialog/TESTS/Makefile b/gnu/lib/libodialog/TESTS/Makefile
new file mode 100644
index 0000000..65e3d71
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/Makefile
@@ -0,0 +1,20 @@
+# Really quick and evil Makefile for building all the tests. I wish that
+# bmake was friendlier to the concept of multiple progs/libs in the same
+# directory.
+#
+# $FreeBSD$
+
+PROGS= msg yesno prgbox gauge dselect fselect text menu1 menu2 menu3 \
+ input1 input2 check1 check2 check3 radio1 radio2 radio3 \
+ ftree1 ftree2 tree
+
+WARNS?= 2
+CFLAGS+= -Wall -Wstrict-prototypes
+LDFLAGS+= -ldialog
+
+all: ${PROGS}
+
+clean:
+ rm -f ${PROGS}
+
+.include <bsd.prog.mk>
diff --git a/gnu/lib/libodialog/TESTS/check1.c b/gnu/lib/libodialog/TESTS/check1.c
new file mode 100644
index 0000000..a2bec62
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/check1.c
@@ -0,0 +1,83 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Hook functions */
+
+static int
+getBool(dialogMenuItem *self)
+{
+ if (self->data && *((int *)self->data))
+ return TRUE;
+ return FALSE;
+}
+
+static int
+setBool(dialogMenuItem *self)
+{
+ if (self->data) {
+ *((int *)self->data) = !*((int *)self->data);
+ return DITEM_SUCCESS;
+ }
+ return DITEM_FAILURE;
+}
+
+static int german_book, italian_book, slang_book;
+
+static int
+clearBooks(dialogMenuItem *self)
+{
+ german_book = italian_book = slang_book = FALSE;
+ return DITEM_SUCCESS | DITEM_REDRAW;
+}
+
+/* menu2 - A more advanced way of using checked and fire hooks to manipulate the backing-variables directly */
+/* prompt title checked fire sel data */
+static dialogMenuItem menu2[] = {
+ { "German", "Buy book on learning German", getBool, setBool, NULL, &german_book},
+ { "Italian", "Buy book on learning Italian", getBool, setBool, NULL, &italian_book },
+ { "Slang", "Buy book on commonly used insults", getBool, setBool, NULL, &slang_book },
+ { "Clear", "Clear book list", NULL, clearBooks, NULL, NULL, ' ', ' ', ' ' },
+};
+
+/* End of hook functions */
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+ retval = dialog_checklist("this is a dialog_checklist() in action, test #1",
+ "this checklist menu shows off some of the straight-forward features\n"
+ "of the new menu system's check & fire dispatch hooks", -1, -1, 4, -4, menu2, NULL);
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_checklist was %d (%d %d %d)\n", retval, german_book, italian_book, slang_book);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/check2.c b/gnu/lib/libodialog/TESTS/check2.c
new file mode 100644
index 0000000..3608261
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/check2.c
@@ -0,0 +1,105 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Hook functions */
+
+static int
+getBool(dialogMenuItem *self)
+{
+ if (self->data && *((int *)self->data))
+ return TRUE;
+ return FALSE;
+}
+
+static int
+setBool(dialogMenuItem *self)
+{
+ if (self->data) {
+ *((int *)self->data) = !*((int *)self->data);
+ return DITEM_SUCCESS;
+ }
+ return DITEM_FAILURE;
+}
+
+static int german_book, italian_book, slang_book;
+
+static int
+clearBooks(dialogMenuItem *self)
+{
+ german_book = italian_book = slang_book = FALSE;
+ return DITEM_SUCCESS | DITEM_REDRAW;
+}
+
+static int
+buyBooks(dialogMenuItem *self)
+{
+ char foo[256];
+
+ if (german_book || italian_book || slang_book) {
+ strcpy(foo, "Ok, you're buying books on");
+ if (german_book)
+ strcat(foo, " german");
+ if (italian_book)
+ strcat(foo, " italian");
+ if (slang_book)
+ strcat(foo, " slang");
+ }
+ else
+ strcpy(foo, "You're not buying any books?");
+ dialog_mesgbox("This is a direct callback for the `Buy' button", foo, -1, -1);
+ return DITEM_SUCCESS;
+}
+
+/* menu3 - Look mom! We can finally use our own OK and Cancel buttons! */
+/* prompt title checked fire sel data */
+static dialogMenuItem menu3[] = {
+ { "Buy!", NULL, NULL, buyBooks }, /* New "OK" button */
+ { "No Way!", NULL, NULL, NULL }, /* New "Cancel" button */
+ { "German", "Buy books on learning German", getBool, setBool, NULL, &german_book },
+ { "Italian", "Buy books on learning Italian", getBool, setBool, NULL, &italian_book },
+ { "Slang", "Buy books on commonly used insults", getBool, setBool, NULL, &slang_book },
+ { "Clear", "Clear book list", NULL, clearBooks, NULL, NULL, ' ', ' ', ' ' },
+};
+
+/* End of hook functions */
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+ retval = dialog_checklist("this is dialog_checklist() in action, test #2",
+ "Same as before, but now we relabel the buttons and override the OK action.",
+ -1, -1, 4, -4, menu3 + 2, (char *)TRUE);
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_checklist was %d\n", retval);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/check3.c b/gnu/lib/libodialog/TESTS/check3.c
new file mode 100644
index 0000000..f117bd6
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/check3.c
@@ -0,0 +1,92 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Hook functions */
+
+static int
+getBool(dialogMenuItem *self)
+{
+ if (self->data && *((int *)self->data))
+ return TRUE;
+ return FALSE;
+}
+
+static int
+setBool(dialogMenuItem *self)
+{
+ if (self->data) {
+ *((int *)self->data) = !*((int *)self->data);
+ return DITEM_SUCCESS;
+ }
+ return DITEM_FAILURE;
+}
+
+static int german_book, italian_book, slang_book;
+static int spending;
+
+static int
+check(dialogMenuItem *self)
+{
+ return ((int)(intptr_t)self->data == spending);
+}
+
+static int
+spend(dialogMenuItem *self)
+{
+ spending = (int)(intptr_t)self->data;
+ return DITEM_SUCCESS | DITEM_REDRAW;
+}
+
+/* menu4 - Show off a simulated compound menu (group at top is checklist, group at bottom radio) */
+/* prompt title checked fire sel, data lbra mark rbra */
+static dialogMenuItem menu4[] = {
+ { "German", "Buy books on learning German", getBool, setBool, NULL, &german_book },
+ { "Italian","Buy books on learning Italian", getBool, setBool, NULL, &italian_book },
+ { "Slang", "Buy books on commonly used insults", getBool, setBool, NULL, &slang_book },
+ { "-----", "----------------------------------", NULL, NULL, NULL, NULL, ' ', ' ', ' ' },
+ { "1000", "Spend $1,000", check, spend, NULL, (void *)1000, '(', '*', ')' },
+ { "500", "Spend $500", check, spend, NULL, (void *)500, '(', '*', ')' },
+ { "100", "Spend $100", check, spend, NULL, (void *)100, '(', '*', ')' },
+};
+
+/* End of hook functions */
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+
+ retval = dialog_checklist("this is dialog_checklist() in action, test #3",
+ "Now we show off some of the button 'styles' one can create.",
+ -1, -1, 7, -7, menu4, NULL);
+ dialog_clear();
+ fprintf(stderr, "spent $%d on %s%s%s books\n", spending, german_book ? " german" : "",
+ italian_book ? " italian" : "", slang_book ? " slang" : "");
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/dselect.c b/gnu/lib/libodialog/TESTS/dselect.c
new file mode 100644
index 0000000..1110379
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/dselect.c
@@ -0,0 +1,41 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+ retval = dialog_dselect(".", "*");
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_dselect was %d\n", retval);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/fselect.c b/gnu/lib/libodialog/TESTS/fselect.c
new file mode 100644
index 0000000..6cefaf3
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/fselect.c
@@ -0,0 +1,44 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ char *retval;
+
+ init_dialog();
+
+ retval = dialog_fselect(".", "*.[ch]");
+ dialog_clear();
+ if (retval)
+ fprintf(stderr, "returned value for dialog_fselect was %s\n", retval);
+ else
+ fprintf(stderr, "returned value for dialog_fselect was NULL\n");
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/ftree1.c b/gnu/lib/libodialog/TESTS/ftree1.c
new file mode 100644
index 0000000..f21e0e5
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/ftree1.c
@@ -0,0 +1,45 @@
+/*
+ * ftree1.c
+ *
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1998, Anatoly A. Orehovsky
+ *
+ * file ./ftree1.test with xterm widget tree from
+ * direct editres(1) dump needed !!!
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dialog.h>
+
+int
+main(int argc, char **argv)
+{
+ int retval;
+ unsigned char *tresult;
+
+ init_dialog();
+ retval = dialog_ftree("ftree1.test", '\t',
+ "ftree dialog box example",
+ "xterm widget tree from direct editres(1) dump",
+ -1, -1, 15,
+ &tresult);
+
+ dialog_update();
+
+ dialog_clear();
+
+ end_dialog();
+
+ if (!retval)
+ {
+ puts(tresult);
+ free(tresult);
+ }
+
+ exit(retval);
+}
diff --git a/gnu/lib/libodialog/TESTS/ftree1.test b/gnu/lib/libodialog/TESTS/ftree1.test
new file mode 100644
index 0000000..4a8f0fa
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/ftree1.test
@@ -0,0 +1,73 @@
+XTerm login
+ VendorShellExt shellext
+ VT100 vt100
+ SimpleMenu fontMenu
+ SmeBSB menuLabel
+ SmeBSB fontdefault
+ SmeBSB font1
+ SmeBSB font2
+ SmeBSB font3
+ SmeBSB font4
+ SmeBSB font5
+ SmeBSB font6
+ SmeBSB fontescape
+ SmeBSB fontsel
+ SimpleMenu mainMenu
+ SmeBSB menuLabel
+ SmeBSB securekbd
+ SmeBSB allowsends
+ SmeBSB redraw
+ SmeLine line1
+ SmeBSB 8-bit control
+ SmeBSB sun function-keys
+ SmeLine line2
+ SmeBSB suspend
+ SmeBSB continue
+ SmeBSB interrupt
+ SmeBSB hangup
+ SmeBSB terminate
+ SmeBSB kill
+ SmeLine line3
+ SmeBSB quit
+ SimpleMenu vtMenu
+ SmeBSB menuLabel
+ SmeBSB scrollbar
+ SmeBSB jumpscroll
+ SmeBSB reversevideo
+ SmeBSB autowrap
+ SmeBSB reversewrap
+ SmeBSB autolinefeed
+ SmeBSB appcursor
+ SmeBSB appkeypad
+ SmeBSB scrollkey
+ SmeBSB scrollttyoutput
+ SmeBSB allow132
+ SmeBSB cursesemul
+ SmeBSB visualbell
+ SmeBSB marginbell
+ SmeBSB altscreen
+ SmeLine line1
+ SmeBSB softreset
+ SmeBSB hardreset
+ SmeBSB clearsavedlines
+ SmeLine line2
+ SmeBSB tekshow
+ SmeBSB tekmode
+ SmeBSB vthide
+ TopLevelShell tektronix
+ VendorShellExt shellext
+ Tek4014 tek4014
+ SimpleMenu tekMenu
+ SmeBSB menuLabel
+ SmeBSB tektextlarge
+ SmeBSB tektext2
+ SmeBSB tektext3
+ SmeBSB tektextsmall
+ SmeLine line1
+ SmeBSB tekpage
+ SmeBSB tekreset
+ SmeBSB tekcopy
+ SmeLine line2
+ SmeBSB vtshow
+ SmeBSB vtmode
+ SmeBSB tekhide
diff --git a/gnu/lib/libodialog/TESTS/ftree2.c b/gnu/lib/libodialog/TESTS/ftree2.c
new file mode 100644
index 0000000..aa4663a
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/ftree2.c
@@ -0,0 +1,47 @@
+/*
+ * ftree2.c
+ *
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1998, Anatoly A. Orehovsky
+ *
+ * file ./ftree2.test with xterm widget tree from
+ * preprocess editres(1) dump needed !!!
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dialog.h>
+
+int
+main(int argc, char **argv)
+{
+ int retval;
+ unsigned char *tresult;
+
+ init_dialog();
+ use_helpfile("ftree2.test");
+ use_helpline("Press Arrows, Tab, Enter or F1");
+ retval = dialog_ftree("ftree2.test", '\t',
+ "ftree dialog box example",
+ "xterm widget tree from preprocess editres(1) dump",
+ -1, -1, 15,
+ &tresult);
+
+ dialog_update();
+
+ dialog_clear();
+
+ end_dialog();
+
+ if (!retval)
+ {
+ puts(tresult);
+ free(tresult);
+ }
+
+ exit(retval);
+}
diff --git a/gnu/lib/libodialog/TESTS/ftree2.test b/gnu/lib/libodialog/TESTS/ftree2.test
new file mode 100644
index 0000000..0850862
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/ftree2.test
@@ -0,0 +1,73 @@
+XTerm login
+XTerm login VendorShellExt shellext
+XTerm login VT100 vt100
+XTerm login SimpleMenu fontMenu
+XTerm login SimpleMenu fontMenu SmeBSB menuLabel
+XTerm login SimpleMenu fontMenu SmeBSB fontdefault
+XTerm login SimpleMenu fontMenu SmeBSB font1
+XTerm login SimpleMenu fontMenu SmeBSB font2
+XTerm login SimpleMenu fontMenu SmeBSB font3
+XTerm login SimpleMenu fontMenu SmeBSB font4
+XTerm login SimpleMenu fontMenu SmeBSB font5
+XTerm login SimpleMenu fontMenu SmeBSB font6
+XTerm login SimpleMenu fontMenu SmeBSB fontescape
+XTerm login SimpleMenu fontMenu SmeBSB fontsel
+XTerm login SimpleMenu mainMenu
+XTerm login SimpleMenu mainMenu SmeBSB menuLabel
+XTerm login SimpleMenu mainMenu SmeBSB securekbd
+XTerm login SimpleMenu mainMenu SmeBSB allowsends
+XTerm login SimpleMenu mainMenu SmeBSB redraw
+XTerm login SimpleMenu mainMenu SmeLine line1
+XTerm login SimpleMenu mainMenu SmeBSB 8-bit control
+XTerm login SimpleMenu mainMenu SmeBSB sun function-keys
+XTerm login SimpleMenu mainMenu SmeLine line2
+XTerm login SimpleMenu mainMenu SmeBSB suspend
+XTerm login SimpleMenu mainMenu SmeBSB continue
+XTerm login SimpleMenu mainMenu SmeBSB interrupt
+XTerm login SimpleMenu mainMenu SmeBSB hangup
+XTerm login SimpleMenu mainMenu SmeBSB terminate
+XTerm login SimpleMenu mainMenu SmeBSB kill
+XTerm login SimpleMenu mainMenu SmeLine line3
+XTerm login SimpleMenu mainMenu SmeBSB quit
+XTerm login SimpleMenu vtMenu
+XTerm login SimpleMenu vtMenu SmeBSB menuLabel
+XTerm login SimpleMenu vtMenu SmeBSB scrollbar
+XTerm login SimpleMenu vtMenu SmeBSB jumpscroll
+XTerm login SimpleMenu vtMenu SmeBSB reversevideo
+XTerm login SimpleMenu vtMenu SmeBSB autowrap
+XTerm login SimpleMenu vtMenu SmeBSB reversewrap
+XTerm login SimpleMenu vtMenu SmeBSB autolinefeed
+XTerm login SimpleMenu vtMenu SmeBSB appcursor
+XTerm login SimpleMenu vtMenu SmeBSB appkeypad
+XTerm login SimpleMenu vtMenu SmeBSB scrollkey
+XTerm login SimpleMenu vtMenu SmeBSB scrollttyoutput
+XTerm login SimpleMenu vtMenu SmeBSB allow132
+XTerm login SimpleMenu vtMenu SmeBSB cursesemul
+XTerm login SimpleMenu vtMenu SmeBSB visualbell
+XTerm login SimpleMenu vtMenu SmeBSB marginbell
+XTerm login SimpleMenu vtMenu SmeBSB altscreen
+XTerm login SimpleMenu vtMenu SmeLine line1
+XTerm login SimpleMenu vtMenu SmeBSB softreset
+XTerm login SimpleMenu vtMenu SmeBSB hardreset
+XTerm login SimpleMenu vtMenu SmeBSB clearsavedlines
+XTerm login SimpleMenu vtMenu SmeLine line2
+XTerm login SimpleMenu vtMenu SmeBSB tekshow
+XTerm login SimpleMenu vtMenu SmeBSB tekmode
+XTerm login SimpleMenu vtMenu SmeBSB vthide
+XTerm login TopLevelShell tektronix
+XTerm login TopLevelShell tektronix VendorShellExt shellext
+XTerm login TopLevelShell tektronix Tek4014 tek4014
+XTerm login SimpleMenu tekMenu
+XTerm login SimpleMenu tekMenu SmeBSB menuLabel
+XTerm login SimpleMenu tekMenu SmeBSB tektextlarge
+XTerm login SimpleMenu tekMenu SmeBSB tektext2
+XTerm login SimpleMenu tekMenu SmeBSB tektext3
+XTerm login SimpleMenu tekMenu SmeBSB tektextsmall
+XTerm login SimpleMenu tekMenu SmeLine line1
+XTerm login SimpleMenu tekMenu SmeBSB tekpage
+XTerm login SimpleMenu tekMenu SmeBSB tekreset
+XTerm login SimpleMenu tekMenu SmeBSB tekcopy
+XTerm login SimpleMenu tekMenu SmeLine line2
+XTerm login SimpleMenu tekMenu SmeBSB vtshow
+XTerm login SimpleMenu tekMenu SmeBSB vtmode
+XTerm login SimpleMenu tekMenu SmeBSB tekhide
diff --git a/gnu/lib/libodialog/TESTS/gauge.c b/gnu/lib/libodialog/TESTS/gauge.c
new file mode 100644
index 0000000..bf0cfc9
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/gauge.c
@@ -0,0 +1,41 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int i;
+
+ init_dialog();
+
+ for (i = 0; i <= 100; i++) {
+ dialog_gauge("Gas tank", "When this gets 100% full, you'd better yank out the nozzle!", 10, 1, 7, 70, i);
+ usleep(30000);
+ }
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/input1.c b/gnu/lib/libodialog/TESTS/input1.c
new file mode 100644
index 0000000..3751071
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/input1.c
@@ -0,0 +1,45 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+ unsigned char result[128];
+
+ init_dialog();
+
+ strcpy(result, "not this!");
+ retval = dialog_inputbox("this is dialog_inputbox() in action, test #1",
+ "Enter something really profound below, please.",
+ -1, -1, result);
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_inputbox was %d (%s)\n", retval, result);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/input2.c b/gnu/lib/libodialog/TESTS/input2.c
new file mode 100644
index 0000000..827c052
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/input2.c
@@ -0,0 +1,47 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+ unsigned char result[128];
+
+ init_dialog();
+
+ result[0]='\0';
+ DialogInputAttrs |= DITEM_NO_ECHO;
+ retval = dialog_inputbox("this is dialog_inputbox() in action, test #2 (no echo)",
+ "Enter something really secret below, please.",
+ -1, -1, result);
+ DialogInputAttrs &= DITEM_NO_ECHO;
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_inputbox was %d (%s)\n", retval, result);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/menu1.c b/gnu/lib/libodialog/TESTS/menu1.c
new file mode 100644
index 0000000..640157a
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/menu1.c
@@ -0,0 +1,96 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Start of hook functions */
+static enum { nowhere, berlin, rome, ny } where;
+
+static int
+_menu1_berlin_action(dialogMenuItem *self)
+{
+ if (where == berlin) {
+ dialog_mesgbox("excuse me?", "But you're already *in* Berlin!", -1, -1);
+ }
+ else {
+ where = berlin;
+ dialog_mesgbox("whoosh!", "Welcome to Berlin! Have a beer!", -1, -1);
+ }
+ return DITEM_SUCCESS | DITEM_RESTORE | DITEM_CONTINUE;
+}
+
+static int
+_menu1_rome_action(dialogMenuItem *self)
+{
+ if (where == rome) {
+ dialog_mesgbox("The wine must be getting to you..", "You're already in Rome!", -1, -1);
+ }
+ else {
+ where = rome;
+ dialog_mesgbox("whoosh!", "Welcome to Rome! Have a coffee!", -1, -1);
+ }
+ return DITEM_SUCCESS | DITEM_RESTORE | DITEM_CONTINUE;
+}
+
+static int
+_menu1_ny_action(dialogMenuItem *self)
+{
+ if (where == ny) {
+ dialog_mesgbox("Say what?", "You're already there!", -1, -1);
+ }
+ else {
+ where = ny;
+ dialog_mesgbox("whoosh!", "Welcome to New York! Now go someplace else!", -1, -1);
+ }
+ return DITEM_SUCCESS | DITEM_RESTORE | DITEM_CONTINUE;
+}
+
+/* menu1 - show off the "fire" action hook */
+/* prompt title checked fire */
+static dialogMenuItem menu1[] = {
+ { "Berlin", "Go visit Germany's new capitol", NULL, _menu1_berlin_action },
+ { "Rome", "Go visit the Roman ruins", NULL, _menu1_rome_action },
+ { "New York", "Go visit the streets of New York", NULL, _menu1_ny_action },
+};
+
+/* End of hook functions */
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+ retval = dialog_menu("this is dialog_menu() in action, test #1",
+ "this simple menu shows off some of the straight-forward features\n"
+ "of the new menu system's action dispatch hooks. Select Cancel to leave",
+ -1, -1, 3, -3, menu1, NULL, NULL, NULL);
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_menu was %d\n", retval);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/menu2.c b/gnu/lib/libodialog/TESTS/menu2.c
new file mode 100644
index 0000000..1545cd8
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/menu2.c
@@ -0,0 +1,96 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Start of hook functions */
+static enum { nowhere, berlin, rome, ny } where;
+
+static int
+_menu1_berlin_action(dialogMenuItem *self)
+{
+ if (where == berlin)
+ dialog_mesgbox("excuse me?", "But you're already *in* Berlin!", -1, -1);
+ else {
+ where = berlin;
+ dialog_mesgbox("whoosh!", "Welcome to Berlin! Have a beer!", -1, -1);
+ }
+ return DITEM_SUCCESS | DITEM_RESTORE | DITEM_CONTINUE;
+}
+
+static int
+_menu1_rome_action(dialogMenuItem *self)
+{
+ if (where == rome)
+ dialog_mesgbox("The wine must be getting to you..", "You're already in Rome!", -1, -1);
+ else {
+ where = rome;
+ dialog_mesgbox("whoosh!", "Welcome to Rome! Have a coffee!", -1, -1);
+ }
+ return DITEM_SUCCESS | DITEM_RESTORE | DITEM_CONTINUE;
+}
+
+static int
+_menu1_ny_action(dialogMenuItem *self)
+{
+ if (where == ny)
+ dialog_mesgbox("Say what?", "You're already there!", -1, -1);
+ else {
+ where = ny;
+ dialog_mesgbox("whoosh!", "Welcome to New York! Now go someplace else!", -1, -1);
+ }
+ return DITEM_SUCCESS | DITEM_RESTORE | DITEM_CONTINUE;
+}
+
+/* menu1 - show off the "fire" action hook */
+/* prompt title checked fire */
+static dialogMenuItem menu1[] = {
+ { "Berlin", "Go visit Germany's new capitol", NULL, _menu1_berlin_action },
+ { "Rome", "Go visit the Roman ruins", NULL, _menu1_rome_action },
+ { "New York", "Go visit the streets of New York", NULL, _menu1_ny_action },
+};
+
+/* End of hook functions */
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+ use_helpfile("menu2.c");
+ use_helpline("Type F1 to view the source for this demo");
+ retval = dialog_menu("this is dialog_menu() in action, test #2",
+ "this simple menu shows off some of the straight-forward features\n"
+ "of the new menu system's action dispatch hooks as well as a helpline\n"
+ "and a helpfile. Select Cancel to leave",
+ -1, -1, 3, -3, menu1, NULL, NULL, NULL);
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_menu was %d\n", retval);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/menu3.c b/gnu/lib/libodialog/TESTS/menu3.c
new file mode 100644
index 0000000..3a7a137
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/menu3.c
@@ -0,0 +1,107 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Hook functions */
+
+static int
+stop(dialogMenuItem *self)
+{
+ dialog_mesgbox("!", "I'm no idiot!", -1, -1);
+ return DITEM_SUCCESS;
+}
+
+static int
+maybe(dialogMenuItem *self)
+{
+ dialog_mesgbox("!", "I said don't rush me! I'm THINKING!", -1, -1);
+ return DITEM_SUCCESS | DITEM_RESTORE | DITEM_CONTINUE;
+}
+
+/* Dummy menu just to show of the ability */
+static char *insurance[] = {
+ "1,000,000", "Mondo insurance policy", "Off",
+ "5,000,000", "Mega insurance policy", "Off",
+ "10,000,000", "Friend! Most Favored customer!", "On"
+};
+
+static void
+preinsure(dialogMenuItem *self, int is_selected)
+{
+ if (is_selected) {
+ static WINDOW *w;
+
+ /* This has to be here first if you want to see selection traverse properly in the invoking menu */
+ refresh();
+
+ w = dupwin(newscr);
+ DialogX = 1;
+ DialogY = 13;
+ dialog_radiolist("How much insurance would you like to take out?",
+ "If you're really going to do this, we recommend some insurance\n"
+ "first! What kind of life insurance policy would you like?",
+ -1, -1, 3, 3, insurance, NULL);
+ touchwin(w);
+ wrefresh(w);
+ delwin(w);
+ }
+}
+
+/*
+ * Show a simple menu that puts up a sub menu when a certain item is traversed to
+ */
+
+/* prompt title checked fire sel */
+static dialogMenuItem doit[] = {
+ { "Rah!" },
+ { "No way!" },
+ { "Stop", "No, I'm not going to do that!", NULL, stop, NULL },
+ { "Maybe", "I'm still thinking about it, don't rush me!", NULL, maybe, NULL, },
+ { "Go", "Yes! Yes! I want to do it!", NULL, NULL, preinsure },
+};
+
+/* End of hook functions */
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+
+ DialogX = 5;
+ DialogY = 1;
+ retval = dialog_menu("Do you have the GUTS?",
+ "C'mon, macho man! Do you have what it takes to do something REALLY\n"
+ "dangerous and stupid? WHAT ARE YOU WAITING FOR?!",
+ -1, -1, 3, -3, doit + 2, (char *)TRUE, NULL, NULL);
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_menu was %d\n", retval);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/msg.c b/gnu/lib/libodialog/TESTS/msg.c
new file mode 100644
index 0000000..c6f590f
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/msg.c
@@ -0,0 +1,42 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+ retval = dialog_msgbox("This is dialog_msgbox() in action with pause on", "Hi there. Please press return now.",
+ -1, -1, 1);
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_msgbox was %d\n", retval);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/prgbox.c b/gnu/lib/libodialog/TESTS/prgbox.c
new file mode 100644
index 0000000..2da4611
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/prgbox.c
@@ -0,0 +1,41 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+ retval = dialog_prgbox("This is dialog_prgbox() in action with cal(1)", "cal", 14, 50, TRUE, TRUE);
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_prgbox was %d\n", retval);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/radio1.c b/gnu/lib/libodialog/TESTS/radio1.c
new file mode 100644
index 0000000..c4eeffd
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/radio1.c
@@ -0,0 +1,71 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Hook functions */
+
+static int spending;
+
+static int
+check(dialogMenuItem *self)
+{
+ return ((int)(intptr_t)self->data == spending);
+}
+
+static int
+spend(dialogMenuItem *self)
+{
+ spending = (int)(intptr_t)self->data;
+ return DITEM_SUCCESS | DITEM_REDRAW;
+}
+
+/* menu5 - Show a simple radiolist menu that inherits the radio appearance by default */
+/* prompt title checked fire sel data */
+static dialogMenuItem menu5[] = {
+ { "1000", "Spend $1,000", check, spend, NULL, (void *)1000 },
+ { "500", "Spend $500", check, spend, NULL, (void *)500 },
+ { "100", "Spend $100", check, spend, NULL, (void *)100 },
+};
+
+/* End of hook functions */
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+
+ retval = dialog_radiolist("this is dialog_radiolist() in action, test #1",
+ "this radio menu shows off some of the straight-forward features\n"
+ "of the new menu system's check & fire dispatch hooks", -1, -1, 3, -3, menu5, NULL);
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_radiolist was %d (money set to %d)\n", retval, spending);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/radio2.c b/gnu/lib/libodialog/TESTS/radio2.c
new file mode 100644
index 0000000..15e353c
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/radio2.c
@@ -0,0 +1,89 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Hook functions */
+
+static char bachelor[10], bachelette[10];
+
+static int
+getBachelor(dialogMenuItem *self)
+{
+ return !strcmp(bachelor, self->prompt);
+}
+
+static int
+setBachelor(dialogMenuItem *self)
+{
+ strcpy(bachelor, self->prompt);
+ return DITEM_SUCCESS | DITEM_REDRAW;
+}
+
+static int
+getBachelette(dialogMenuItem *self)
+{
+ return !strcmp(bachelette, self->prompt);
+}
+
+static int
+setBachelette(dialogMenuItem *self)
+{
+ strcpy(bachelette, self->prompt);
+ return DITEM_SUCCESS | DITEM_REDRAW;
+}
+
+/* menu6- More complex radiolist menu that creates two groups in a single menu */
+/* prompt title checked fire */
+static dialogMenuItem menu6[] = {
+ { "Tom", "Tom's a dynamic shoe salesman from Tulsa, OK!", getBachelor, setBachelor },
+ { "Dick", "Dick's a retired engine inspector from McDonnell-Douglas!", getBachelor, setBachelor },
+ { "Harry", "Harry's a professional female impersonator from Las Vegas!", getBachelor, setBachelor },
+ { "-----", "----------------------------------", NULL, NULL, NULL, NULL, ' ', ' ', ' ' },
+ { "Jane", "Jane's a twice-divorced housewife from Moose, Oregon!", getBachelette, setBachelette },
+ { "Sally", "Sally's a shy Human Resources Manager for IBM!", getBachelette, setBachelette },
+ { "Mary", "Mary's an energetic serial killer on the lam!", getBachelette, setBachelette },
+};
+
+/* End of hook functions */
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+ retval = dialog_radiolist("this is dialog_radiolist() in action, test #2",
+ "Welcome to \"The Love Blender!\" - America's favorite game show\n"
+ "where YOU, the contestant, get to choose which of these two\n"
+ "fine specimens of humanity will go home together, whether they\n"
+ "like it or not!", -1, -1, 7, -7, menu6, NULL);
+ dialog_clear();
+ fprintf(stderr, "I'm sure that %s and %s will be very happy together!\n", bachelor, bachelette);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/radio3.c b/gnu/lib/libodialog/TESTS/radio3.c
new file mode 100644
index 0000000..2175358
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/radio3.c
@@ -0,0 +1,98 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Hook functions */
+
+static int spending;
+
+static int
+check(dialogMenuItem *self)
+{
+ return ((int)(intptr_t)self->data == spending);
+}
+
+static int
+spend(dialogMenuItem *self)
+{
+ spending = (int)(intptr_t)self->data;
+ return DITEM_SUCCESS | DITEM_REDRAW;
+}
+
+static void
+ask(dialogMenuItem *self, int is_selected)
+{
+ if (is_selected) {
+ char *str;
+
+ if (!strcmp(self->prompt, "1000"))
+ str = "You'd better ask both your parents first! ";
+ else if (!strcmp(self->prompt, "500"))
+ str = "You'd better at least ask your Dad! ";
+ else
+ str = "Yes, being frugal is probably a good idea!";
+ DialogX = 15;
+ DialogY = 17;
+ dialog_msgbox("Free Advice", str, -1, -1, 0);
+ }
+}
+
+/*
+ * menu5 - Show a simple radiolist menu that inherits the radio appearance by default and appears at
+ * a different location, leaving room for a msg box below it. This shows off the DialogX/DialogY extensions.
+ */
+
+/* prompt title checked fire sel data */
+static dialogMenuItem menu5[] = {
+ { "1000", "Spend $1,000", check, spend, ask, (void *)1000 },
+ { "500", "Spend $500", check, spend, ask, (void *)500 },
+ { "100", "Spend $100", check, spend, ask, (void *)100 },
+};
+
+/* End of hook functions */
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+
+ DialogX = 5;
+ DialogY = 1;
+ retval = dialog_radiolist("this is dialog_radiolist() in action, test #3",
+ "This radio menu shows off the ability to put dialog menus and other\n"
+ "controls at different locations, as well as the `selected' hook which\n"
+ "lets you follow the traversal of the selection bar as well as what's\n"
+ "selected.",
+ -1, -1, 3, -3, menu5, NULL);
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_radiolist was %d (money set to %d)\n", retval, spending);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/text.c b/gnu/lib/libodialog/TESTS/text.c
new file mode 100644
index 0000000..e071937
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/text.c
@@ -0,0 +1,41 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int retval;
+
+ init_dialog();
+
+ retval = dialog_textbox("This is dialog_textbox() in action with /etc/passwd", "/etc/passwd", 10, 60);
+ dialog_clear();
+ fprintf(stderr, "returned value for dialog_textbox was %d\n", retval);
+
+ end_dialog();
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TESTS/tree.c b/gnu/lib/libodialog/TESTS/tree.c
new file mode 100644
index 0000000..c69b52e
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/tree.c
@@ -0,0 +1,111 @@
+/*
+ * tree.c
+ *
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1998, Anatoly A. Orehovsky
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dialog.h>
+
+unsigned char *names[] = {
+ "/",
+ "/dev",
+ "/dev/fd",
+ "/tmp",
+ "/usr",
+ "/var",
+ "/home",
+ "/stand",
+ "/stand/etc",
+ "/stand/en_US.ISO8859-1",
+ "/stand/info",
+ "/stand/info/bin",
+ "/stand/info/des",
+ "/stand/info/games",
+ "/stand/info/manpages",
+ "/stand/info/proflibs",
+ "/stand/info/dict",
+ "/stand/info/info",
+ "/stand/info/src",
+ "/etc",
+ "/etc/gnats",
+ "/etc/kerberosIV",
+ "/etc/mtree",
+ "/etc/namedb",
+ "/etc/ppp",
+ "/etc/uucp",
+ "/etc/sliphome",
+ "/proc",
+ "/lkm",
+ "/mnt",
+ "/root",
+ "/sbin",
+ "/bin",
+ 0
+};
+
+unsigned char *names1[] = {
+ "a",
+ "a:b",
+ "a:b:c",
+ "a:d"
+};
+
+int
+main(int argc, char **argv)
+{
+ int retval;
+ unsigned char *tresult;
+ char comstr[BUFSIZ];
+
+ init_dialog();
+ do {
+ use_helpline("Press OK for listing directory");
+ retval = dialog_tree(names,
+ sizeof(names)/sizeof(unsigned char *) - 1,
+ '/',
+ "tree dialog box example",
+ "Typical find -x / -type d output",
+ -1, -1, 15,
+ &tresult);
+
+ if (retval)
+ break;
+
+ use_helpline(NULL);
+ (void)snprintf(comstr, sizeof(comstr),
+ "ls -CF %s", tresult);
+
+ retval = dialog_prgbox(
+ comstr,
+ comstr, 20, 60, TRUE, TRUE);
+
+ dialog_clear();
+
+ retval = dialog_tree(names1,
+ sizeof(names1)/sizeof(unsigned char *),
+ ':',
+ "tree dialog box example",
+ "Other tree",
+ -1, -1, 5,
+ &tresult);
+ if (!retval)
+ {
+ dialog_clear();
+ }
+ } while (!retval);
+
+ dialog_update();
+
+ dialog_clear();
+
+ end_dialog();
+
+ exit(retval);
+}
diff --git a/gnu/lib/libodialog/TESTS/yesno.c b/gnu/lib/libodialog/TESTS/yesno.c
new file mode 100644
index 0000000..647b51c
--- /dev/null
+++ b/gnu/lib/libodialog/TESTS/yesno.c
@@ -0,0 +1,45 @@
+/*
+ * small test-driver for new dialog functionality
+ *
+ * Copyright (c) 1995, Jordan Hubbard
+ *
+ * All rights reserved.
+ *
+ * This source code may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of the software nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <dialog.h>
+
+/* Kick it off, James! */
+int
+main(int argc, char **argv)
+{
+ int rval1, rval2;
+
+ init_dialog();
+
+ rval1 = dialog_yesno("This is dialog_yesno() in action",
+ "Have you stopped deliberately putting bugs into your code?", -1, -1);
+ dialog_clear();
+ rval2 = dialog_noyes("This is dialog_noyes() in action",
+ "Have you stopped beating your wife?", -1, -1);
+ dialog_clear();
+ end_dialog();
+ fprintf(stderr, "returned value for dialog_yesno was %d\n", rval1);
+ fprintf(stderr, "returned value for dialog_noyes was %d\n", rval2);
+ return 0;
+}
diff --git a/gnu/lib/libodialog/TODO b/gnu/lib/libodialog/TODO
new file mode 100644
index 0000000..132a4a4
--- /dev/null
+++ b/gnu/lib/libodialog/TODO
@@ -0,0 +1,36 @@
+- cut off names in the listbox that are to long
+done 27Jan95
+ The current behaviour may not be desirable. When browsing through
+ long names these, when highlighted, will be shown with the first
+ characters cut off, when not highlighted the last characters will
+ be cut off.
+
+- look at behaviour of TAB key when browsing through directories.
+done 28Jan95
+
+- make sure the full name of the directory is written to the
+ "Directory:"-box
+done 28Jan95
+
+- mark current selections in listbox when initializing the listobject
+Idontknow
+- test and use Notify() when checking for error conditions
+ok
+- test overall
+- adapt color of buttons when changing focus to the button.
+done 28Jan95
+- add shade to dialog_fselect()-window
+done 29Jan95
+- add (nn%) indication to lists.
+done 30Jan95
+- add use_helpfile()
+done 13Feb95
+- add use_helpline()
+
+NOTE: apparently there is a bug (or a strange interaction between pkg_manage
+and dialog_textbox) in dialog_textbox. When I use this routine to display
+the helpfile in display_helpfile() the program gets mysterious segmentation
+faults and bus errors.
+I now use dialog_mesgbox, after I have read the file into a buffer.
+
+
diff --git a/gnu/lib/libodialog/checklist.c b/gnu/lib/libodialog/checklist.c
new file mode 100644
index 0000000..e349ca6
--- /dev/null
+++ b/gnu/lib/libodialog/checklist.c
@@ -0,0 +1,661 @@
+/*
+ * checklist.c -- implements the checklist box
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * Substantial rennovation: 12/18/95, Jordan K. Hubbard
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dialog.h>
+#include "dialog.priv.h"
+
+
+static void print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int status, int choice, int selected, dialogMenuItem *me, int list_width, int item_x, int check_x);
+
+#define DREF(di, item) ((di) ? &((di)[(item)]) : NULL)
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ */
+int
+dialog_checklist(unsigned char *title, unsigned char *prompt, int height, int width,
+ int list_height, int cnt, void *it, unsigned char *result)
+{
+ int i, j, x, y, cur_x, cur_y, old_x, old_y, box_x, box_y, key = 0, button,
+ choice, l, k, scroll, max_choice, item_no = 0, *status;
+ int redraw_menu = FALSE, cursor_reset = FALSE;
+ int rval = 0, onlist = 1, ok_space, cancel_space;
+ char okButton, cancelButton;
+ WINDOW *dialog, *list;
+ unsigned char **items = NULL;
+ dialogMenuItem *ditems;
+ int list_width, check_x, item_x;
+
+ /* Allocate space for storing item on/off status */
+ if ((status = alloca(sizeof(int) * abs(cnt))) == NULL) {
+ endwin();
+ fprintf(stderr, "\nCan't allocate memory in dialog_checklist().\n");
+ exit(-1);
+ }
+
+draw:
+ choice = scroll = button = 0;
+ /* Previous calling syntax, e.g. just a list of strings? */
+ if (cnt >= 0) {
+ items = it;
+ ditems = NULL;
+ item_no = cnt;
+ /* Initializes status */
+ for (i = 0; i < item_no; i++)
+ status[i] = !strcasecmp(items[i*3 + 2], "on");
+ }
+ /* It's the new specification format - fake the rest of the code out */
+ else {
+ item_no = abs(cnt);
+ ditems = it;
+ if (!items)
+ items = (unsigned char **)alloca((item_no * 3) * sizeof(unsigned char *));
+
+ /* Initializes status */
+ for (i = 0; i < item_no; i++) {
+ status[i] = ditems[i].checked ? ditems[i].checked(&ditems[i]) : FALSE;
+ items[i*3] = ditems[i].prompt;
+ items[i*3 + 1] = ditems[i].title;
+ items[i*3 + 2] = status[i] ? "on" : "off";
+ }
+ }
+ max_choice = MIN(list_height, item_no);
+
+ check_x = 0;
+ item_x = 0;
+ /* Find length of longest item in order to center checklist */
+ for (i = 0; i < item_no; i++) {
+ l = strlen(items[i*3]);
+ for (j = 0; j < item_no; j++) {
+ k = strlen(items[j*3 + 1]);
+ check_x = MAX(check_x, l + k + 6);
+ }
+ item_x = MAX(item_x, l);
+ }
+ if (height < 0)
+ height = strheight(prompt)+list_height+4+2;
+ if (width < 0) {
+ i = strwidth(prompt);
+ j = ((title != NULL) ? strwidth(title) : 0);
+ width = MAX(i,j);
+ width = MAX(width,check_x+4)+4;
+ }
+ width = MAX(width,24);
+
+ if (width > COLS)
+ width = COLS;
+ if (height > LINES)
+ height = LINES;
+ /* center dialog box on screen */
+ x = (COLS - width)/2;
+ y = (LINES - height)/2;
+
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(stdscr, y, x, height, width);
+#endif
+ dialog = newwin(height, width, y, x);
+ if (dialog == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width, y, x);
+ return -1;
+ }
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+ wattrset(dialog, border_attr);
+ wmove(dialog, height-3, 0);
+ waddch(dialog, ACS_LTEE);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dialog_attr);
+ waddch(dialog, ACS_RTEE);
+ wmove(dialog, height-2, 1);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ' ');
+
+ if (title != NULL) {
+ wattrset(dialog, title_attr);
+ wmove(dialog, 0, (width - strlen(title))/2 - 1);
+ waddch(dialog, ' ');
+ waddstr(dialog, title);
+ waddch(dialog, ' ');
+ }
+ wattrset(dialog, dialog_attr);
+ wmove(dialog, 1, 2);
+ print_autowrap(dialog, prompt, height - 1, width - 2, width, 1, 2, TRUE, FALSE);
+
+ list_width = width - 6;
+ getyx(dialog, cur_y, cur_x);
+ box_y = cur_y + 1;
+ box_x = (width - list_width) / 2 - 1;
+
+ /* create new window for the list */
+ list = subwin(dialog, list_height, list_width, y + box_y + 1, x + box_x + 1);
+ if (list == NULL) {
+ delwin(dialog);
+ endwin();
+ fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", list_height, list_width,
+ y + box_y + 1, x + box_x + 1);
+ return -1;
+ }
+ keypad(list, TRUE);
+
+ /* draw a box around the list items */
+ draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, menubox_border_attr, menubox_attr);
+
+ check_x = (list_width - check_x) / 2;
+ item_x = check_x + item_x + 6;
+
+ /* Print the list */
+ for (i = 0; i < max_choice; i++)
+ print_item(list, items[i * 3], items[i * 3 + 1], status[i], i, i == choice, DREF(ditems, i), list_width, item_x, check_x);
+ wnoutrefresh(list);
+ print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
+
+ display_helpline(dialog, height - 1, width);
+
+ x = width / 2 - 11;
+ y = height - 2;
+ /* Is this a fancy new style argument string where we get to override
+ * the buttons, or an old style one where they're fixed?
+ */
+ if (ditems && result) {
+ cancelButton = toupper(ditems[CANCEL_BUTTON].prompt[0]);
+ print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : FALSE);
+ okButton = toupper(ditems[OK_BUTTON].prompt[0]);
+ print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : TRUE);
+ }
+ else {
+ cancelButton = 'C';
+ print_button(dialog, "Cancel", y, x + 14, FALSE);
+ okButton = 'O';
+ print_button(dialog, " OK ", y, x, TRUE);
+ }
+ wnoutrefresh(dialog);
+ wmove(list, choice, check_x+1);
+ wrefresh(list);
+
+ /*
+ * XXX Black magic voodoo that allows printing to the checklist
+ * window. For some reason, if this "refresh" code is not in
+ * place, printing to the window from the selected callback
+ * prints "behind" the checklist window. There is probably a
+ * better way to do this.
+ */
+ draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, menubox_border_attr, menubox_attr);
+
+ for (i = 0; i < max_choice; i++)
+ print_item(list, items[i * 3], items[i * 3 + 1], status[i], i, i == choice, DREF(ditems, i), list_width, item_x, check_x);
+ print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
+
+ wmove(list, choice, check_x+1);
+ wnoutrefresh(dialog);
+ wrefresh(list);
+ /* XXX Black magic XXX */
+
+ while (key != ESC) {
+ key = wgetch(dialog);
+
+ /* Shortcut to OK? */
+ if (toupper(key) == okButton) {
+ if (ditems) {
+ if (result && ditems[OK_BUTTON].fire) {
+ int st;
+ WINDOW *save;
+
+ save = dupwin(newscr);
+ st = ditems[OK_BUTTON].fire(&ditems[OK_BUTTON]);
+ if (st & DITEM_RESTORE) {
+ touchwin(save);
+ wrefresh(save);
+ }
+ delwin(save);
+ }
+ }
+ else if (result) {
+ *result = '\0';
+ for (i = 0; i < item_no; i++) {
+ if (status[i]) {
+ strcat(result, items[i*3]);
+ strcat(result, "\n");
+ }
+ }
+ }
+ rval = 0;
+ key = ESC; /* Lemme out! */
+ break;
+ }
+
+ /* Shortcut to cancel? */
+ if (toupper(key) == cancelButton) {
+ if (ditems && result && ditems[CANCEL_BUTTON].fire) {
+ int st;
+ WINDOW *save;
+
+ save = dupwin(newscr);
+ st = ditems[CANCEL_BUTTON].fire(&ditems[CANCEL_BUTTON]);
+ if (st & DITEM_RESTORE) {
+ touchwin(save);
+ wrefresh(save);
+ wmove(dialog, cur_y, cur_x);
+ }
+ delwin(save);
+ }
+ rval = 1;
+ key = ESC; /* I gotta go! */
+ break;
+ }
+
+ /* Check if key pressed matches first character of any item tag in list */
+ for (i = 0; i < max_choice; i++)
+ if (key != ' ' && key < 0x100 && toupper(key) == toupper(items[(scroll+i)*3][0]))
+ break;
+
+ if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) ||
+ KEY_IS_UP(key) || KEY_IS_DOWN(key) || ((key == ' ' || key == '\n' ||
+ key == '\r') && onlist)) {
+
+ /* if moving from buttons to the list, reset and redraw buttons */
+ if (!onlist) {
+ onlist = 1;
+ button = 0;
+
+ if (ditems && result) {
+ print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
+ print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
+ }
+ else {
+ print_button(dialog, "Cancel", y, x + 14, button);
+ print_button(dialog, " OK ", y, x, !button);
+ }
+ wmove(list, choice, check_x+1);
+ wnoutrefresh(dialog);
+ wrefresh(list);
+ }
+
+ if (key >= '1' && key <= MIN('9', '0'+max_choice))
+ i = key - '1';
+
+ else if (KEY_IS_UP(key)) {
+ if (!choice) {
+ if (scroll) {
+ /* Scroll list down */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ if (list_height > 1) {
+ /* De-highlight current first item before scrolling down */
+ print_item(list, items[scroll * 3], items[scroll * 3 + 1], status[scroll], 0,
+ FALSE, DREF(ditems, scroll), list_width, item_x, check_x);
+ scrollok(list, TRUE);
+ wscrl(list, -1);
+ scrollok(list, FALSE);
+ }
+ scroll--;
+ print_item(list, items[scroll*3], items[scroll*3 + 1], status[scroll], 0,
+ TRUE, DREF(ditems, scroll), list_width, item_x, check_x);
+ print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
+ wmove(list, choice, check_x+1);
+ wnoutrefresh(dialog);
+ wrefresh(list);
+ }
+ continue; /* wait for another key press */
+ }
+ else
+ i = choice - 1;
+ }
+ else if (KEY_IS_DOWN(key)) {
+ if (choice == max_choice - 1) {
+ if (scroll + choice < item_no - 1) {
+ /* Scroll list up */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ if (list_height > 1) {
+ /* De-highlight current last item before scrolling up */
+ print_item(list, items[(scroll + max_choice - 1) * 3],
+ items[(scroll + max_choice - 1) * 3 + 1],
+ status[scroll + max_choice - 1], max_choice - 1,
+ FALSE, DREF(ditems, scroll + max_choice - 1), list_width, item_x, check_x);
+ scrollok(list, TRUE);
+ scroll(list);
+ scrollok(list, FALSE);
+ }
+ scroll++;
+ print_item(list, items[(scroll + max_choice - 1) * 3],
+ items[(scroll + max_choice - 1) * 3 + 1],
+ status[scroll + max_choice - 1], max_choice - 1, TRUE,
+ DREF(ditems, scroll + max_choice - 1), list_width, item_x, check_x);
+ print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
+ wmove(list, choice, check_x+1);
+ wnoutrefresh(dialog);
+ wrefresh(list);
+ }
+ continue; /* wait for another key press */
+ }
+ else
+ i = choice + 1;
+ }
+ else if ((key == ' ' || key == '\n' || key == '\r') && onlist) { /* Toggle item status */
+ char lbra = 0, rbra = 0, mark = 0;
+
+ getyx(list, old_y, old_x); /* Save cursor position */
+
+ if (ditems) {
+ if (ditems[scroll + choice].fire) {
+ int st;
+ WINDOW *save;
+
+ save = dupwin(newscr);
+ st = ditems[scroll + choice].fire(&ditems[scroll + choice]); /* Call "fire" action */
+ if (st & DITEM_RESTORE) {
+ touchwin(save);
+ wrefresh(save);
+ }
+ delwin(save);
+ if (st & DITEM_REDRAW) {
+ wclear(list);
+ for (i = 0; i < item_no; i++)
+ status[i] = ditems[i].checked ? ditems[i].checked(&ditems[i]) : FALSE;
+ for (i = 0; i < max_choice; i++) {
+ print_item(list, items[(scroll + i) * 3], items[(scroll + i) * 3 + 1],
+ status[scroll + i], i, i == choice, DREF(ditems, scroll + i), list_width, item_x, check_x);
+ }
+ wnoutrefresh(list);
+ print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4,
+ cur_x, cur_y);
+ wrefresh(dialog);
+ }
+ if (st & DITEM_LEAVE_MENU) {
+ /* Allow a fire action to take us out of the menu */
+ key = ESC;
+ rval = 0;
+ break;
+ }
+ else if (st & DITEM_RECREATE) {
+ delwin(list);
+ delwin(dialog);
+ dialog_clear();
+ goto draw;
+ }
+ }
+ status[scroll + choice] = ditems[scroll + choice].checked ?
+ ditems[scroll + choice].checked(&ditems[scroll + choice]) : FALSE;
+ lbra = ditems[scroll + choice].lbra;
+ rbra = ditems[scroll + choice].rbra;
+ mark = ditems[scroll + choice].mark;
+ }
+ else
+ status[scroll + choice] = !status[scroll + choice];
+ wmove(list, choice, check_x);
+ wattrset(list, check_selected_attr);
+ if (!lbra)
+ lbra = '[';
+ if (!rbra)
+ rbra = ']';
+ if (!mark)
+ mark = 'X';
+ wprintw(list, "%c%c%c", lbra, status[scroll + choice] ? mark : ' ', rbra);
+ wmove(list, old_y, old_x); /* Restore cursor to previous position */
+ wrefresh(list);
+ continue; /* wait for another key press */
+ }
+
+ if (i != choice) {
+ /* De-highlight current item */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ print_item(list, items[(scroll + choice) * 3], items[(scroll + choice) * 3 + 1],
+ status[scroll + choice], choice, FALSE, DREF(ditems, scroll + choice), list_width, item_x, check_x);
+
+ /* Highlight new item */
+ choice = i;
+ print_item(list, items[(scroll + choice) * 3], items[(scroll + choice) * 3 + 1], status[scroll + choice], choice, TRUE, DREF(ditems, scroll + choice), list_width, item_x, check_x);
+ wmove(list, choice, check_x+1); /* Restore cursor to previous position */
+ wrefresh(list);
+ }
+ continue; /* wait for another key press */
+ }
+
+ switch (key) {
+ case KEY_PPAGE: /* can we go up? */
+ if (scroll > height - 4)
+ scroll -= (height-4);
+ else
+ scroll = 0;
+ redraw_menu = TRUE;
+ if (!onlist) {
+ onlist = 1;
+ button = 0;
+ }
+ break;
+
+ case KEY_NPAGE: /* can we go down a full page? */
+ if (scroll + list_height >= item_no-1 - list_height) {
+ scroll = item_no - list_height;
+ if (scroll < 0)
+ scroll = 0;
+ }
+ else
+ scroll += list_height;
+ redraw_menu = TRUE;
+ if (!onlist) {
+ onlist = 1;
+ button = 0;
+ }
+ break;
+
+ case KEY_HOME: /* go to the top */
+ scroll = 0;
+ choice = 0;
+ redraw_menu = TRUE;
+ cursor_reset = TRUE;
+ onlist = 1;
+ break;
+
+ case KEY_END: /* Go to the bottom */
+ scroll = item_no - list_height;
+ if (scroll < 0)
+ scroll = 0;
+ choice = max_choice - 1;
+ redraw_menu = TRUE;
+ cursor_reset = TRUE;
+ onlist = 1;
+ break;
+
+ case TAB:
+ case KEY_BTAB:
+ /* move to next component */
+ if (onlist) { /* on list, next is ok button */
+ onlist = 0;
+ if (ditems && result) {
+ print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
+ print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
+ ok_space = 1;
+ cancel_space = strlen(ditems[OK_BUTTON].prompt) + 6;
+ }
+ else {
+ print_button(dialog, "Cancel", y, x + 14, button);
+ print_button(dialog, " OK ", y, x, !button);
+ ok_space = 3;
+ cancel_space = 15;
+ }
+ if (button)
+ wmove(dialog, y, x + cancel_space);
+ else
+ wmove(dialog, y, x + ok_space);
+ wrefresh(dialog);
+ break;
+ }
+ else if (button) { /* on cancel button, next is list */
+ button = 0;
+ onlist = 1;
+ redraw_menu = TRUE;
+ break;
+ }
+ /* on ok button, next is cancel button, same as left/right case */
+
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ onlist = 0;
+ button = !button;
+ if (ditems && result) {
+ print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
+ print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
+ ok_space = 1;
+ cancel_space = strlen(ditems[OK_BUTTON].prompt) + 6;
+ }
+ else {
+ print_button(dialog, "Cancel", y, x + 14, button);
+ print_button(dialog, " OK ", y, x, !button);
+ ok_space = 3;
+ cancel_space = 15;
+ }
+ if (button)
+ wmove(dialog, y, x + cancel_space);
+ else
+ wmove(dialog, y, x + ok_space);
+ wrefresh(dialog);
+ break;
+
+ case ' ':
+ case '\n':
+ case '\r':
+ if (!onlist) {
+ if (ditems) {
+ if (result && ditems[button ? CANCEL_BUTTON : OK_BUTTON].fire) {
+ int st;
+ WINDOW *save = dupwin(newscr);
+
+ st = ditems[button ? CANCEL_BUTTON : OK_BUTTON].fire(&ditems[button ? CANCEL_BUTTON : OK_BUTTON]);
+ if (st & DITEM_RESTORE) {
+ touchwin(save);
+ wrefresh(save);
+ }
+ delwin(save);
+ if (st == DITEM_FAILURE)
+ continue;
+ }
+ }
+ else if (result) {
+ *result = '\0';
+ for (i = 0; i < item_no; i++) {
+ if (status[i]) {
+ strcat(result, items[i*3]);
+ strcat(result, "\n");
+ }
+ }
+ }
+ rval = button;
+ key = ESC; /* Bail out! */
+ break;
+ }
+
+ /* Let me outta here! */
+ case ESC:
+ rval = -1;
+ break;
+
+ /* Help! */
+ case KEY_F(1):
+ case '?':
+ display_helpfile();
+ break;
+ }
+
+ if (redraw_menu) {
+ getyx(list, old_y, old_x);
+ wclear(list);
+
+ /*
+ * Re-draw a box around the list items. It is required
+ * if amount of list items is smaller than height of listbox.
+ * Otherwise un-redrawn field will be filled with default
+ * screen attributes instead of dialog attributes.
+ */
+ draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2, menubox_border_attr, menubox_attr);
+
+ for (i = 0; i < max_choice; i++)
+ print_item(list, items[(scroll + i) * 3], items[(scroll + i) * 3 + 1], status[scroll + i], i, i == choice, DREF(ditems, scroll + i), list_width, item_x, check_x);
+ print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
+
+ /* redraw buttons to fix highlighting */
+ if (ditems && result) {
+ print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
+ print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
+ }
+ else {
+ print_button(dialog, "Cancel", y, x + 14, button);
+ print_button(dialog, " OK ", y, x, !button);
+ }
+ wnoutrefresh(dialog);
+ if (cursor_reset) {
+ wmove(list, choice, check_x+1);
+ cursor_reset = FALSE;
+ }
+ else {
+ wmove(list, old_y, old_x);
+ }
+ wrefresh(list);
+ redraw_menu = FALSE;
+ }
+ }
+ delwin(list);
+ delwin(dialog);
+ return rval;
+}
+
+
+/*
+ * Print list item
+ */
+static void
+print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int status, int choice, int selected, dialogMenuItem *me, int list_width, int item_x, int check_x)
+{
+ int i;
+
+ /* Clear 'residue' of last item */
+ wattrset(win, menubox_attr);
+ wmove(win, choice, 0);
+ for (i = 0; i < list_width; i++)
+ waddch(win, ' ');
+ wmove(win, choice, check_x);
+ wattrset(win, selected ? check_selected_attr : check_attr);
+ wprintw(win, "%c%c%c", me && me->lbra ? me->lbra : '[',
+ status ? me && me->mark ? me->mark : 'X' : ' ',
+ me && me->rbra ? me->rbra : ']');
+ wattrset(win, menubox_attr);
+ waddch(win, ' ');
+ wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
+ waddch(win, tag[0]);
+ wattrset(win, selected ? tag_selected_attr : tag_attr);
+ waddstr(win, tag + 1);
+ wmove(win, choice, item_x);
+ wattrset(win, selected ? item_selected_attr : item_attr);
+ waddstr(win, item);
+ /* If have a selection handler for this, call it */
+ if (me && me->selected) {
+ wrefresh(win);
+ me->selected(me, selected);
+ }
+}
+/* End of print_item() */
diff --git a/gnu/lib/libodialog/colors.h b/gnu/lib/libodialog/colors.h
new file mode 100644
index 0000000..7cea0a0
--- /dev/null
+++ b/gnu/lib/libodialog/colors.h
@@ -0,0 +1,219 @@
+/*
+ * colors.h -- color attribute definitions
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ * Default color definitions
+ *
+ * *_FG = foreground
+ * *_BG = background
+ * *_HL = highlight?
+ */
+#define SCREEN_FG COLOR_CYAN
+#define SCREEN_BG COLOR_BLUE
+#define SCREEN_HL TRUE
+
+#define SHADOW_FG COLOR_BLACK
+#define SHADOW_BG COLOR_BLACK
+#define SHADOW_HL TRUE
+
+#define DIALOG_FG COLOR_BLACK
+#define DIALOG_BG COLOR_WHITE
+#define DIALOG_HL FALSE
+
+#define TITLE_FG COLOR_YELLOW
+#define TITLE_BG COLOR_WHITE
+#define TITLE_HL TRUE
+
+#define BORDER_FG COLOR_WHITE
+#define BORDER_BG COLOR_WHITE
+#define BORDER_HL TRUE
+
+#define BUTTON_ACTIVE_FG COLOR_WHITE
+#define BUTTON_ACTIVE_BG COLOR_BLUE
+#define BUTTON_ACTIVE_HL TRUE
+
+#define BUTTON_INACTIVE_FG COLOR_BLACK
+#define BUTTON_INACTIVE_BG COLOR_WHITE
+#define BUTTON_INACTIVE_HL FALSE
+
+#define BUTTON_KEY_ACTIVE_FG COLOR_WHITE
+#define BUTTON_KEY_ACTIVE_BG COLOR_BLUE
+#define BUTTON_KEY_ACTIVE_HL TRUE
+
+#define BUTTON_KEY_INACTIVE_FG COLOR_RED
+#define BUTTON_KEY_INACTIVE_BG COLOR_WHITE
+#define BUTTON_KEY_INACTIVE_HL FALSE
+
+#define BUTTON_LABEL_ACTIVE_FG COLOR_YELLOW
+#define BUTTON_LABEL_ACTIVE_BG COLOR_BLUE
+#define BUTTON_LABEL_ACTIVE_HL TRUE
+
+#define BUTTON_LABEL_INACTIVE_FG COLOR_BLACK
+#define BUTTON_LABEL_INACTIVE_BG COLOR_WHITE
+#define BUTTON_LABEL_INACTIVE_HL TRUE
+
+#define INPUTBOX_FG COLOR_BLACK
+#define INPUTBOX_BG COLOR_WHITE
+#define INPUTBOX_HL FALSE
+
+#define INPUTBOX_BORDER_FG COLOR_BLACK
+#define INPUTBOX_BORDER_BG COLOR_WHITE
+#define INPUTBOX_BORDER_HL FALSE
+
+#define SEARCHBOX_FG COLOR_BLACK
+#define SEARCHBOX_BG COLOR_WHITE
+#define SEARCHBOX_HL FALSE
+
+#define SEARCHBOX_TITLE_FG COLOR_YELLOW
+#define SEARCHBOX_TITLE_BG COLOR_WHITE
+#define SEARCHBOX_TITLE_HL TRUE
+
+#define SEARCHBOX_BORDER_FG COLOR_WHITE
+#define SEARCHBOX_BORDER_BG COLOR_WHITE
+#define SEARCHBOX_BORDER_HL TRUE
+
+#define POSITION_INDICATOR_FG COLOR_YELLOW
+#define POSITION_INDICATOR_BG COLOR_WHITE
+#define POSITION_INDICATOR_HL TRUE
+
+#define MENUBOX_FG COLOR_BLACK
+#define MENUBOX_BG COLOR_WHITE
+#define MENUBOX_HL FALSE
+
+#define MENUBOX_BORDER_FG COLOR_WHITE
+#define MENUBOX_BORDER_BG COLOR_WHITE
+#define MENUBOX_BORDER_HL TRUE
+
+#define ITEM_FG COLOR_BLACK
+#define ITEM_BG COLOR_WHITE
+#define ITEM_HL FALSE
+
+#define ITEM_SELECTED_FG COLOR_WHITE
+#define ITEM_SELECTED_BG COLOR_BLUE
+#define ITEM_SELECTED_HL TRUE
+
+#define TAG_FG COLOR_YELLOW
+#define TAG_BG COLOR_WHITE
+#define TAG_HL TRUE
+
+#define TAG_SELECTED_FG COLOR_YELLOW
+#define TAG_SELECTED_BG COLOR_BLUE
+#define TAG_SELECTED_HL TRUE
+
+#define TAG_KEY_FG COLOR_RED
+#define TAG_KEY_BG COLOR_WHITE
+#define TAG_KEY_HL TRUE
+
+#define TAG_KEY_SELECTED_FG COLOR_RED
+#define TAG_KEY_SELECTED_BG COLOR_BLUE
+#define TAG_KEY_SELECTED_HL TRUE
+
+#define CHECK_FG COLOR_BLACK
+#define CHECK_BG COLOR_WHITE
+#define CHECK_HL FALSE
+
+#define CHECK_SELECTED_FG COLOR_WHITE
+#define CHECK_SELECTED_BG COLOR_BLUE
+#define CHECK_SELECTED_HL TRUE
+
+#define UARROW_FG COLOR_GREEN
+#define UARROW_BG COLOR_WHITE
+#define UARROW_HL TRUE
+
+#define DARROW_FG COLOR_GREEN
+#define DARROW_BG COLOR_WHITE
+#define DARROW_HL TRUE
+
+/* End of default color definitions */
+
+#define C_ATTR(x,y) ((x ? A_BOLD : 0) | COLOR_PAIR((y)))
+#define COLOR_NAME_LEN 10
+#define COLOR_COUNT 8
+
+
+/*
+ * Global variables
+ */
+
+typedef struct {
+ unsigned char name[COLOR_NAME_LEN];
+ int value;
+} color_names_st;
+
+
+#ifdef __DIALOG_MAIN__
+
+/*
+ * For matching color names with color values
+ */
+color_names_st color_names[] = {
+ {"BLACK", COLOR_BLACK},
+ {"RED", COLOR_RED},
+ {"GREEN", COLOR_GREEN},
+ {"YELLOW", COLOR_YELLOW},
+ {"BLUE", COLOR_BLUE},
+ {"MAGENTA", COLOR_MAGENTA},
+ {"CYAN", COLOR_CYAN},
+ {"WHITE", COLOR_WHITE},
+}; /* color names */
+
+
+/*
+ * Table of color values
+ */
+int color_table[][3] = {
+ {SCREEN_FG, SCREEN_BG, SCREEN_HL },
+ {SHADOW_FG, SHADOW_BG, SHADOW_HL },
+ {DIALOG_FG, DIALOG_BG, DIALOG_HL },
+ {TITLE_FG, TITLE_BG, TITLE_HL },
+ {BORDER_FG, BORDER_BG, BORDER_HL },
+ {BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL },
+ {BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL },
+ {BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL },
+ {BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG, BUTTON_KEY_INACTIVE_HL },
+ {BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG, BUTTON_LABEL_ACTIVE_HL },
+ {BUTTON_LABEL_INACTIVE_FG,BUTTON_LABEL_INACTIVE_BG,BUTTON_LABEL_INACTIVE_HL},
+ {INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL },
+ {INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL },
+ {SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL },
+ {SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL },
+ {SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL },
+ {POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL },
+ {MENUBOX_FG, MENUBOX_BG, MENUBOX_HL },
+ {MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL },
+ {ITEM_FG, ITEM_BG, ITEM_HL },
+ {ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL },
+ {TAG_FG, TAG_BG, TAG_HL },
+ {TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL },
+ {TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL },
+ {TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL },
+ {CHECK_FG, CHECK_BG, CHECK_HL },
+ {CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL },
+ {UARROW_FG, UARROW_BG, UARROW_HL },
+ {DARROW_FG, DARROW_BG, DARROW_HL },
+}; /* color_table */
+
+#else
+
+extern color_names_st color_names[];
+extern int color_table[][3];
+
+#endif /* __DIALOG_MAIN__ */
diff --git a/gnu/lib/libodialog/dialog.3 b/gnu/lib/libodialog/dialog.3
new file mode 100644
index 0000000..2e4b8fb
--- /dev/null
+++ b/gnu/lib/libodialog/dialog.3
@@ -0,0 +1,842 @@
+.\"
+.\" Copyright (c) 1995, Jordan Hubbard
+.\"
+.\" All rights reserved.
+.\"
+.\" This manual page may be used, modified, copied, distributed, and
+.\" sold, in both source and binary form provided that the above
+.\" copyright and these terms are retained, verbatim, as the first
+.\" lines of this file. Under no circumstances is the author
+.\" responsible for the proper functioning of the software described herein
+.\" nor does the author assume any responsibility for damages incurred with
+.\" its use.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 1, 2000
+.Dt DIALOG 3
+.Os
+.Sh NAME
+.Nm draw_shadow ,
+.Nm draw_box ,
+.Nm line_edit ,
+.Nm strheight ,
+.Nm strwidth ,
+.Nm dialog_create_rc ,
+.Nm dialog_yesno ,
+.Nm dialog_noyes ,
+.Nm dialog_prgbox ,
+.Nm dialog_msgbox ,
+.Nm dialog_textbox ,
+.Nm dialog_menu ,
+.Nm dialog_checklist ,
+.Nm dialog_radiolist ,
+.Nm dialog_inputbox ,
+.Nm dialog_clear_norefresh ,
+.Nm dialog_clear ,
+.Nm dialog_update ,
+.Nm dialog_fselect ,
+.Nm dialog_notify ,
+.Nm dialog_mesgbox ,
+.Nm dialog_gauge ,
+.Nm init_dialog ,
+.Nm end_dialog ,
+.Nm use_helpfile ,
+.Nm use_helpline ,
+.Nm get_helpline ,
+.Nm restore_helpline ,
+.Nm dialog_ftree ,
+.Nm dialog_tree
+.Nd provide a simple ncurses-based GUI interface
+.Sh SYNOPSIS
+.In dialog.h
+.Ft "void"
+.Fn draw_shadow "WINDOW *win" "int y" "int x" "int height" "int width"
+.Ft "void"
+.Fn draw_box "WINDOW *win" "int y" "int x" "int height" "int width" "chtype box" "chtype border"
+.Ft "int"
+.Fo line_edit
+.Fa "WINDOW *dialog"
+.Fa "int box_y"
+.Fa "int box_x"
+.Fa "int flen"
+.Fa "int box_width"
+.Fa "chtype attr"
+.Fa "int first"
+.Fa "unsigned char *result"
+.Fa "int attr_mask"
+.Fc
+.Ft "int"
+.Fn strheight "const char *p"
+.Ft "int"
+.Fn strwidth "const char *p"
+.Ft "void"
+.Fn dialog_create_rc "unsigned char *filename"
+.Ft "int"
+.Fn dialog_yesno "unsigned char *title" "unsigned char *prompt" "int height" "int width"
+.Ft "int"
+.Fn dialog_noyes "unsigned char *title" "unsigned char *prompt" "int height" "int width"
+.Ft "int"
+.Fn dialog_prgbox "unsigned char *title" "const unsigned char *line" "int height" "int width" "int pause" "int use_shell"
+.Ft "int"
+.Fn dialog_textbox "unsigned char *title" "unsigned char *file" "int height" "int width"
+.Ft "int"
+.Fo dialog_menu
+.Fa "unsigned char *title"
+.Fa "unsigned char *prompt"
+.Fa "int height"
+.Fa "int width"
+.Fa "int menu_height"
+.Fa "int cnt"
+.Fa "void *it"
+.Fa "unsigned char *result"
+.Fa "int *ch"
+.Fa "int *sc"
+.Fc
+.Ft "int"
+.Fn dialog_checklist "unsigned char *title" "unsigned char *prompt" "int height" "int width" "int list_height" "int cnt" "void *it" "unsigned char *result"
+.Ft "int"
+.Fn dialog_radiolist "unsigned char *title" "unsigned char *prompt" "int height" "int width" "int list_height" "int cnt" "void *it" "unsigned char *result"
+.Ft "int"
+.Fn dialog_inputbox "unsigned char *title" "unsigned char *prompt" "int height" "int width" "unsigned char *result"
+.Ft "char *"
+.Fn dialog_fselect "char *dir" "char *fmask"
+.Ft "int"
+.Fn dialog_dselect "char *dir" "char *fmask"
+.Ft "void"
+.Fn dialog_notify "char *msg"
+.Ft "int"
+.Fn dialog_mesgbox "unsigned char *title" "unsigned char *prompt" "int height" "int width"
+.Ft "void"
+.Fn dialog_gauge "char *title" "char *prompt" "int y" "int x" "int height" "int width" "int perc"
+.Ft "void"
+.Fn use_helpfile "char *hfile"
+.Ft "void"
+.Fn use_helpline "char *hline"
+.Ft "char *"
+.Fn get_helpline "void"
+.Ft "void"
+.Fn dialog_clear_norefresh "void"
+.Ft "void"
+.Fn dialog_clear "void"
+.Ft "void"
+.Fn dialog_update "void"
+.Ft "void"
+.Fn init_dialog "void"
+.Ft "void"
+.Fn end_dialog "void"
+.Ft "int"
+.Fn dialog_ftree "unsigned char *filename" "unsigned char FS" "unsigned char *title" "unsigned char *prompt" "int height" "int width" "int menu_height" "unsigned char **result"
+.Ft "int"
+.Fo dialog_tree
+.Fa "unsigned char **names"
+.Fa "int size"
+.Fa "unsigned char FS"
+.Fa "unsigned char *title"
+.Fa "unsigned char *prompt"
+.Fa "int height"
+.Fa "int width"
+.Fa "int menu_height"
+.Fa "unsigned char **result"
+.Fc
+.Sh DESCRIPTION
+The dialog library attempts to provide a fairly simplistic set of
+fixed-presentation menus, input boxes, gauges, file requestors and
+other general purpose GUI (a bit of a stretch, since it uses
+ncurses) objects.
+Since the library also had its roots in a
+shell-script writer's utility (see the
+.Xr dialog 1
+command), the
+early API was somewhat primitively based on strings being passed in or
+out and parsed.
+This API was later extended to take either the
+original arguments or arrays of
+.Va dialogMenuItem
+structures,
+giving the user much more control over the internal behavior of each
+control.
+The
+.Va dialogMenuItem
+structure internals are public:
+.Bd -literal -offset indent
+typedef struct _dmenu_item {
+ char *prompt;
+ char *title;
+ int (*checked)(struct _dmenu_item *self);
+ int (*fire)(struct _dmenu_item *self);
+ int (*selected)(struct _dmenu_item *self, int is_selected);
+ void *data;
+ char lbra, mark, rbra;
+ long aux;
+} dialogMenuItem;
+.Ed
+.Pp
+The
+.Dv prompt
+and
+.Dv title
+strings are pretty much self-explanatory,
+and the
+.Va checked
+and
+.Va fire
+function pointers provide optional
+display and action hooks (the
+.Dv data
+variable being available for
+the convenience of those hooks) when more tightly coupled feedback between
+a menu object and user code is required.
+The
+.Va selected
+hook also
+allows you to verify whether or not a given item is selected (the cursor is
+over it) for implementing pretty much any possible context-sensitive
+behavior.
+A number of clever tricks for simulating various kinds of item
+types can also be done by adjusting the values of
+.Va lbra
+(default: '['),
+.Va mark
+(default: '*' for radio menus, 'X' for check menus)
+and
+.Va rbra
+(default: ']') and declaring a reasonable
+.Va checked
+hook,
+which should return TRUE for the
+.Dq marked
+state and FALSE for
+.Dq unmarked .
+The
+.Va aux
+field is not used internally, and is available for miscellaneous usage.
+If an item has a
+.Va fire
+hook associated with it, it will also be called
+whenever the item is "toggled" in some way and should return one of the
+following codes:
+.Bd -literal -offset 4n
+#define DITEM_SUCCESS 0 /* Successful completion */
+#define DITEM_FAILURE 1 /* Failed to "fire" */
+.Ed
+.Pp
+The following flags are in the upper 16 bits of return status:
+.Bd -literal -offset 4n
+#define DITEM_LEAVE_MENU (1 << 16)
+#define DITEM_REDRAW (1 << 17)
+#define DITEM_RECREATE (1 << 18)
+#define DITEM_RESTORE (1 << 19)
+#define DITEM_CONTINUE (1 << 20)
+.Ed
+.Pp
+Two special globals also exist for putting a dialog at any arbitrary
+X,Y location (the early designers rather short-sightedly made no provisions
+for this).
+If set to zero, the default centering behavior will be in
+effect.
+.Pp
+Below is a short description of the various functions:
+.Pp
+The
+.Fn draw_shadow
+function draws a shadow in curses window
+.Va win
+using the dimensions of
+.Va x , y , width
+and
+.Va height .
+.Pp
+The
+.Fn draw_box
+function draws a bordered box using the dimensions of
+.Va x , y , width
+and
+.Va height .
+The attributes from
+.Va box
+and
+.Va border
+are used, if specified, while painting the box and border regions of the
+object.
+.Pp
+The
+.Fn line_edit
+function invokes a simple line editor with an edit box of dimensions
+.Va box_x , box_y
+and
+.Va box_width .
+The field length is constrained by
+.Va flen ,
+starting at the
+.Va first
+character specified and
+optionally displayed with character attributes
+.Va attr .
+The string being edited is stored in
+.Va result .
+Returns 0 on success, 1 on Cancel, and -1 on failure or ESC.
+.Pp
+The
+.Fn strheight
+function returns the height of string in
+.Va p ,
+counting newlines.
+.Pp
+The
+.Fn strwidth
+function returns the width of string in
+.Va p ,
+counting newlines.
+.Pp
+The
+.Fn dialog_create_rc
+function dumps dialog library settings into
+.Pa filename
+for later retrieval as defaults.
+Returns 0 on success, -1 on failure.
+.Pp
+The
+.Fn dialog_yesno
+function displays a text box using
+.Va title
+and
+.Va prompt
+strings of dimensions
+.Va height
+and
+.Va width .
+Also paint a pair of
+.Em Yes
+and
+.Em \&No
+buttons at the bottom.
+The default selection is
+.Em Yes .
+If the
+.Em Yes
+button is chosen, return FALSE.
+If
+.Em \&No ,
+return TRUE.
+.Pp
+The
+.Fn dialog_noyes
+function is the same as
+.Fn dialog_yesno ,
+except the default selection is
+.Em \&No .
+.Pp
+The
+.Fn dialog_prgbox
+function displays a text box of dimensions
+.Va height
+and
+.Va width
+containing the output of command
+.Va line .
+If
+.Va use_shell
+is TRUE,
+.Va line
+is passed as an argument to
+.Xr sh 1 ,
+otherwise it is simply passed to
+.Xr exec 3 .
+If
+.Va pause
+is TRUE, a final confirmation requestor will be put up when execution
+terminates.
+Returns 0 on success, -1 on failure.
+.Pp
+The
+.Fn dialog_textbox
+function displays a text box containing the contents of
+.Va file
+with dimensions of
+.Va height
+and
+.Va width .
+.Pp
+The
+.Fn dialog_menu
+function displays a menu of dimensions
+.Va height
+and
+.Va width
+with an optional internal menu height of
+.Va menu_height .
+The
+.Va cnt
+and
+.Va it
+arguments are of particular importance since they,
+together, determine which of the 2 available APIs to use.
+To use the
+older and traditional interface,
+.Va cnt
+should be a positive
+integer representing the number of string pointer pairs to find in
+.Va it
+(which should be of type
+.Ft char "**" ) ,
+the strings are
+expected to be in prompt and title order for each item and the
+.Va result
+parameter is expected to point to an array where the
+prompt string of the item selected will be copied.
+To use the newer
+interface,
+.Va cnt
+should be a
+.Va negative
+integer representing the number of
+.Va dialogMenuItem
+structures pointed to by
+.Va it
+(which should be of type
+.Vt dialogMenuItem "*" ) ,
+one structure per item.
+In the new interface, the
+.Va result
+variable is used as a simple boolean (not a pointer) and should be NULL if
+.Va it
+only points to menu items and the default OK and Cancel buttons are desired.
+If
+.Va result
+is non-NULL, then
+.Va it
+is actually expected to point 2 locations
+.Va past
+the start of the menu item list.
+.Va it
+is then expected to
+point to an item representing the Cancel button, from which the
+.Va prompt
+and
+.Va fire
+actions are used to override the default behavior, and
+.Va it
+to the same for the OK button.
+.Pp
+Using either API behavior, the
+.Va ch
+and
+.Va sc
+values may be passed in to preserve current
+item selection and scroll position values across calls.
+.Pp
+The
+.Fn dialog_checklist
+function displays a menu of dimensions
+.Va height
+and
+.Va width
+with an
+optional internal menu height of
+.Va list_height .
+The
+.Va cnt
+and
+.Va it
+arguments are of particular importance since they,
+together, determine which of the 2 available APIs to use.
+To use the
+older and traditional interface,
+.Va cnt
+should be a positive
+integer representing the number of string pointer tuples to find in
+.Va it
+(which should be of type
+.Ft "char **" ) ,
+the strings are
+expected to be in prompt, title and state ("on" or "off") order for
+each item and the
+.Va result
+parameter is expected to point to an
+array where the prompt string of the item(s) selected will be
+copied.
+To use the newer interface,
+.Va cnt
+should be a
+.Em negative
+integer representing the number of
+.Ft dialogMenuItem
+structures pointed to by
+.Va it
+(which should be of type
+.Ft "dialogMenuItem *" ) ,
+one structure per item.
+In the new interface,
+the
+.Va result
+variable is used as a simple boolean (not a pointer)
+and should be NULL if
+.Va it
+only points to menu items and the default OK and Cancel
+buttons are desired.
+If
+.Va result
+is non-NULL, then
+.Va it
+is actually expected to
+point 2 locations
+.Va past
+the start of the menu item list.
+.Va it
+is then expected to point to an item representing the Cancel
+button, from which the
+.Va prompt
+and
+.Va fire
+actions are used to override the default behavior, and
+.Va it
+to the same for the OK button.
+.Pp
+In the standard API model, the menu supports the selection of multiple items,
+each of which is marked with an `X' character to denote selection.
+When
+the OK button is selected, the prompt values for all items selected are
+concatenated into the
+.Va result
+string.
+.Pp
+In the new API model, it is not actually necessary to preserve
+"checklist" semantics at all since practically everything about how
+each item is displayed or marked as "selected" is fully configurable.
+You could have a single checklist menu that actually contained a group
+of items with "radio" behavior, "checklist" behavior and standard menu
+item behavior.
+The only reason to call
+.Fn dialog_checklist
+over
+.Fn dialog_radiolist
+in the new API model is to inherit the base
+behavior, you are no longer constrained by it.
+.Pp
+Returns 0 on success, 1 on Cancel, and -1 on failure or ESC.
+.Pp
+The
+.Fn dialog_radiolist
+function displays a menu of dimensions
+.Va height
+and
+.Va width
+with an
+optional internal menu height of
+.Va list_height .
+The
+.Va cnt
+and
+.Va it
+arguments are of particular importance since they,
+together, determine which of the 2 available APIs to use.
+To use the
+older and traditional interface,
+.Va cnt
+should be a positive
+integer representing the number of string pointer tuples to find in
+.Va it
+(which should be of type
+.Ft "char **" ) ,
+the strings are
+expected to be in prompt, title and state ("on" or "off") order for
+each item and the
+.Va result
+parameter is expected to point to an
+array where the prompt string of the item(s) selected will be
+copied.
+To use the newer interface,
+.Va cnt
+should be a
+.Dv negative
+integer representing the number of
+.Ft dialogMenuItem
+structures pointed to by
+.Va it
+(which should be of type
+.Ft "dialogMenuItem *" ,
+one structure per item.
+In the new interface,
+the
+.Va result
+variable is used as a simple boolean (not a pointer)
+and should be NULL if
+.Va it
+only points to menu items and the default OK and Cancel
+buttons are desired.
+If
+.Va result
+is non-NULL, then
+.Va it
+is actually expected to point 2 locations
+.Va past
+the start of the menu item list.
+.Va it
+is then expected to point to an item representing the Cancel
+button, from which the
+.Va prompt
+and
+.Va fire
+actions are used to override the default behavior, and
+.Va it
+does the same for the traditional OK button.
+.Pp
+In the standard API model, the menu supports the selection of only one
+of multiple items, the currently active item marked with an `*'
+character to denote selection.
+When the OK button is selected, the
+prompt value for this item is copied into the
+.Va result
+string.
+.Pp
+In the new API model, it is not actually necessary to preserve
+"radio button" semantics at all since practically everything about how
+each item is displayed or marked as "selected" is fully configurable.
+You could have a single radio menu that actually contained a group
+of items with "checklist" behavior, "radio" behavior and standard menu
+item behavior.
+The only reason to call
+.Fn dialog_radiolist
+over
+.Fn dialog_checklistlist
+in the new API model is to inherit the base
+behavior.
+.Pp
+Returns 0 on success, 1 on Cancel and -1 on failure or ESC.
+.Pp
+The
+.Fn dialog_inputbox
+function displays a single-line text input field in a box displaying
+.Va title
+and
+.Va prompt
+of dimensions
+.Va height
+and
+.Va width .
+The field entered is stored in
+.Va result .
+.Pp
+Returns 0 on success, -1 on failure or ESC.
+.Pp
+The
+.Fn dialog_fselect
+function brings up a file selector dialog starting at
+.Va dir
+and showing only those file names
+matching
+.Va fmask .
+.Pp
+Returns filename selected or NULL.
+.Pp
+The
+.Fn dialog_dselect
+function brings up a directory selector dialog starting at
+.Va dir
+and showing only those directory names
+matching
+.Va fmask .
+.Pp
+Returns directory name selected or NULL.
+.Pp
+The
+.Fn dialog_notify
+function brings up a generic "hey, you!" notifier dialog containing
+.Va msg .
+.Pp
+The
+.Fn dialog_mesgbox
+function displays a notifier dialog, but with more control over
+.Va title ,
+.Va prompt ,
+.Va width
+and
+.Va height .
+This object will also wait for user confirmation, unlike
+.Fn dialog_notify .
+.Pp
+Returns 0 on success, -1 on failure.
+.Pp
+The
+.Fn dialog_gauge
+function displays a horizontal bar-graph style gauge.
+A value of
+.Em 100
+for
+.Em perc
+constitutes a full gauge, a value of
+.Em 0
+an empty one.
+.Pp
+The
+.Fn use_helpfile
+function for any menu supporting context sensitive help, invokes the text box
+object on this file whenever the
+.Em F1
+key is pressed.
+.Pp
+The
+.Fn use_helpline
+function displays this line of helpful text below any menu being displayed.
+.Pp
+The
+.Fn get_helpline
+function gets the current value of the helpful text line.
+.Pp
+The
+.Fn dialog_clear_norefresh
+function clears the screen back to the dialog background color, but do not
+refresh the contents just yet.
+.Pp
+The
+.Fn dialog_clear
+function clears the screen back to the dialog background color immediately.
+.Pp
+The
+.Fn dialog_update
+function does any pending screen refreshes now.
+.Pp
+The
+.Fn init_dialog
+function initializes the dialog library (call this routine before any other
+dialog API calls).
+.Pp
+The
+.Fn end_dialog
+function shuts down the dialog library (call this if you need to get back to
+sanity).
+.Pp
+The
+.Fn dialog_ftree
+function shows a tree described by the data from the file
+.Pa filename .
+The data in the file should look like
+.Xr find 1
+output.
+For the
+.Xr find 1
+output, the field separator
+.Va FS
+will be
+.Dq \&/ .
+If
+.Va height
+and
+.Va width
+are positive numbers, they set the absolute
+size of the whole
+.Fn dialog_ftree
+box.
+If
+.Va height
+and
+.Va width
+are negative numbers, the size of the
+.Fn dialog_ftree
+box will be calculated automatically.
+.Va menu_height
+sets the height of the tree subwindow inside the
+.Fn dialog_ftree
+box and must be set.
+.Va title
+is shown centered on the upper border of the
+.Fn dialog_ftree
+box.
+.Va prompt
+is shown inside the
+.Fn dialog_ftree
+box above the tree subwindow and can contain
+.Ql \e\&n
+to split lines.
+One can navigate in
+the tree by pressing UP/DOWN or
+.Sm off
+.So \&+ Sc \&/ So \&- Sc ,
+.Sm on
+PG_UP/PG_DOWN or
+.Sm off
+.So b Sc \&/SPACE
+.Sm on
+and
+HOME/END or
+.Sm off
+.So g Sc \&/ So G Sc .
+.Sm on
+A leaf of the
+tree is selected by pressing TAB or LEFT/RIGHT the OK
+button and pressing ENTER.
+filename may contain data like
+.Xr find 1
+output, as well as like the output of
+.Xr find 1
+with
+.Fl d
+option.
+Some of the transient paths to the leaves of the tree may
+be absent.
+Such data is corrected when fed from filename.
+.Pp
+The function returns 0 and a pointer to the selected leaf (to the path to
+the leaf from the root of the tree) into result, if the OK button was
+selected.
+The memory allocated for the building of the tree is freed on
+exiting
+.Fn dialog_ftree .
+The memory for the result line should be freed
+later manually, if necessary.
+If the Cancel button was selected, the
+function returns 1.
+In case of exiting
+.Fn dialog_ftree
+on ESC, the function returns -1.
+.Pp
+The
+.Fn dialog_tree
+function returns the same results as
+.Fn dialog_ftree .
+If 0 is returned, result will contain a pointer from the array
+.Va names .
+.\" \fBdialog_tree\fR displays the tree very much like \fBdialog_ftree\fR does,
+.\" with some exceptions. The source data for the building of the tree is an
+.\" array \fBnames\fR of paths to the leaves (should be similar to \fBfind(1)\fR
+.\" output) of the size \fBsize\fR. However, there is no correction of data like
+.\" in \fBdialog_ftree\fR. Thus, to display a correct tree, the array must
+.\" already contain correct data. Besides, in each session every unique use of
+.\" \fBdialog_tree\fR is kept in memory, and later, when calling
+.\" \fBdialog_tree\fR with the same \fBnames\fR, \fBsize\fR, \fBFS\fR,
+.\" \fBheight\fR, \fBwidth\fR and \fBmenu_height\fR the position of the cursor
+.\" in the tree subwindow is restored.
+.Sh SEE ALSO
+.Xr dialog 1 ,
+.Xr ncurses 3
+.Sh HISTORY
+These functions appeared in
+.Fx 2.0
+as the
+.Xr dialog 1
+command and were soon split into a separate library
+and command by
+.An Andrey Chernov .
+.An Marc van Kempen
+implemented most of the extra controls and objects,
+.An Jordan Hubbard
+added the dialogMenuItem renovations and this man page and
+.An Anatoly A. Orehovsky
+implemented
+.Fn dialog_ftree
+and
+.Fn dialog_tree .
+.Sh AUTHORS
+.An -nosplit
+The primary author would appear to be
+.An Savio Lam Aq lam836@cs.cuhk.hk
+with contributions over the years by
+.An Stuart Herbert Aq S.Herbert@sheffield.ac.uk ,
+.An Marc van Kempen Aq wmbfmk@urc.tue.nl ,
+.An Andrey Chernov Aq ache@FreeBSD.org ,
+.An Jordan Hubbard Aq jkh@FreeBSD.org
+and
+.An Anatoly A. Orehovsky Aq tolik@mpeks.tomsk.su .
+.Sh BUGS
+Sure!
diff --git a/gnu/lib/libodialog/dialog.h b/gnu/lib/libodialog/dialog.h
new file mode 100644
index 0000000..369b139
--- /dev/null
+++ b/gnu/lib/libodialog/dialog.h
@@ -0,0 +1,211 @@
+#ifndef _DIALOG_H_INCLUDE
+#define _DIALOG_H_INCLUDE
+
+/*
+ * dialog.h -- common declarations for all dialog modules
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * Substantial rennovation: 12/18/95, Jordan K. Hubbard
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#define HAVE_NCURSES
+
+#ifdef HAVE_NCURSES
+#include <ncurses.h>
+
+#else
+
+#ifdef ultrix
+#include <cursesX.h>
+#else
+#include <curses.h>
+#endif
+
+#endif
+
+/* special return codes for `fire' actions */
+#define DITEM_STATUS(flag) ((flag) & 0x0000FFFF)
+#define DITEM_SUCCESS 0
+#define DITEM_FAILURE 1
+
+/* Flags - returned in upper 16 bits of return status */
+#define DITEM_LEAVE_MENU (1 << 16)
+#define DITEM_REDRAW (1 << 17)
+#define DITEM_RECREATE (1 << 18)
+#define DITEM_RESTORE (1 << 19)
+#define DITEM_CONTINUE (1 << 20)
+
+/* Attributes as used by entry fields right now */
+#define DITEM_NO_ECHO 0x0001
+
+
+/* negative offsets for buttons in item lists, if specified */
+#define OK_BUTTON -2
+#define CANCEL_BUTTON -1
+
+/* for use in describing more exotic behaviors */
+typedef struct _dmenu_item {
+ char *prompt;
+ char *title;
+ int (*checked)(struct _dmenu_item *self);
+ int (*fire)(struct _dmenu_item *self);
+ void (*selected)(struct _dmenu_item *self, int is_selected);
+ void *data;
+ char lbra, mark, rbra;
+ long aux;
+} dialogMenuItem;
+
+#define VERSION "0.4"
+#define MAX_LEN 4096
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+extern int DialogX, DialogY, DialogInputAttrs;
+
+/*
+ * Attribute names
+ */
+#define screen_attr attributes[0]
+#define shadow_attr attributes[1]
+#define dialog_attr attributes[2]
+#define title_attr attributes[3]
+#define border_attr attributes[4]
+#define button_active_attr attributes[5]
+#define button_inactive_attr attributes[6]
+#define button_key_active_attr attributes[7]
+#define button_key_inactive_attr attributes[8]
+#define button_label_active_attr attributes[9]
+#define button_label_inactive_attr attributes[10]
+#define inputbox_attr attributes[11]
+#define inputbox_border_attr attributes[12]
+#define searchbox_attr attributes[13]
+#define searchbox_title_attr attributes[14]
+#define searchbox_border_attr attributes[15]
+#define position_indicator_attr attributes[16]
+#define menubox_attr attributes[17]
+#define menubox_border_attr attributes[18]
+#define item_attr attributes[19]
+#define item_selected_attr attributes[20]
+#define tag_attr attributes[21]
+#define tag_selected_attr attributes[22]
+#define tag_key_attr attributes[23]
+#define tag_key_selected_attr attributes[24]
+#define check_attr attributes[25]
+#define check_selected_attr attributes[26]
+#define uarrow_attr attributes[27]
+#define darrow_attr attributes[28]
+
+/* number of attributes */
+#define ATTRIBUTE_COUNT 29
+
+extern chtype attributes[];
+
+#ifdef HAVE_NCURSES
+extern bool use_shadow;
+void draw_shadow(WINDOW *win, int y, int x, int height, int width);
+#endif
+void draw_box(WINDOW *win, int y, int x, int height, int width, chtype box, chtype border);
+int line_edit(WINDOW *dialog, int box_y, int box_x, int flen, int box_width, chtype attrs, int first, unsigned char *result, int attr_mask);
+int strheight(const char *p);
+int strwidth(const char *p);
+
+void dialog_create_rc(unsigned char *filename);
+int dialog_yesno(unsigned char *title, unsigned char *prompt, int height, int width);
+int dialog_noyes(unsigned char *title, unsigned char *prompt, int height, int width);
+int dialog_prgbox(unsigned char *title, const unsigned char *line, int height, int width, int pause, int use_shell);
+int dialog_msgbox(unsigned char *title, unsigned char *prompt, int height, int width, int pause);
+int dialog_textbox(unsigned char *title, unsigned char *file, int height, int width);
+int dialog_menu(unsigned char *title, unsigned char *prompt, int height, int width, int menu_height,
+ int item_no, void *itptr, unsigned char *result, int *ch, int *sc);
+int dialog_checklist(unsigned char *title, unsigned char *prompt, int height, int width, int list_height,
+ int item_no, void *itptr, unsigned char *result);
+int dialog_radiolist(unsigned char *title, unsigned char *prompt, int height, int width, int list_height,
+ int item_no, void *itptr, unsigned char *result);
+int dialog_inputbox(unsigned char *title, unsigned char *prompt, int height, int width, unsigned char *result);
+void dialog_clear_norefresh(void);
+void dialog_clear(void);
+void dialog_update(void);
+void init_dialog(void);
+void end_dialog(void);
+
+/* Additions to libdialog */
+char *dialog_fselect(char *dir, char *fmask);
+int dialog_dselect(char *dir, char *fmask);
+void dialog_notify(char *msg);
+int dialog_mesgbox(unsigned char *title, unsigned char *prompt, int height, int width);
+void use_helpfile(char *helpfile);
+void use_helpline(char *helpline);
+char *get_helpline(void);
+void restore_helpline(char *helpline);
+void dialog_gauge(char *title, char *prompt, int y, int x, int height, int width, int perc);
+
+/*
+ * Display a tree menu from file
+ *
+ * filename - file with like find(1) output
+ * FS - fields separator
+ * title - title of dialog box
+ * prompt - prompt text into dialog box
+ * height - height of dialog box
+ * width - width of dialog box
+ * menu_height - height of menu box
+ * result - pointer to char array
+ *
+ * return values:
+ * -1 - ESC pressed
+ * 0 - Ok, result set (must be freed later)
+ * 1 - Cancel
+ */
+int dialog_ftree(unsigned char *filename, unsigned char FS,
+ unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ unsigned char **result);
+
+/*
+ * Display a tree menu from array
+ *
+ * names - array with like find(1) output
+ * size - size of array
+ * FS - fields separator
+ * title - title of dialog box
+ * prompt - prompt text into dialog box
+ * height - height of dialog box
+ * width - width of dialog box
+ * menu_height - height of menu box
+ * result - pointer to char array
+ *
+ * return values:
+ * -1 - ESC pressed
+ * 0 - Ok, result set
+ * 1 - Cancel
+ */
+
+int dialog_tree(unsigned char **names, int size, unsigned char FS,
+ unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ unsigned char **result);
+
+#endif /* _DIALOG_H_INCLUDE */
diff --git a/gnu/lib/libodialog/dialog.priv.h b/gnu/lib/libodialog/dialog.priv.h
new file mode 100644
index 0000000..06c01a5
--- /dev/null
+++ b/gnu/lib/libodialog/dialog.priv.h
@@ -0,0 +1,183 @@
+/*
+ * dialog.h -- common declarations for all dialog modules
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#if defined(LOCALE)
+#include <locale.h>
+#endif
+
+
+/*
+ * Change these if you want
+ */
+#define USE_SHADOW TRUE
+#define USE_COLORS TRUE
+
+#define ESC 27
+#define TAB 9
+#define BUF_SIZE (10*1024)
+
+#ifndef MIN
+#define MIN(x,y) (x < y ? x : y)
+#endif
+#ifndef MAX
+#define MAX(x,y) (x > y ? x : y)
+#endif
+
+#ifndef ctrl
+#define ctrl(a) ((a) - 'a' + 1)
+#endif
+
+#ifndef HAVE_NCURSES
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+#endif /* HAVE_NCURSES */
+
+/* Travel key conventions */
+#define KEY_IS_UP(key) ((key) == KEY_UP || (key) == '-' || key == '\020' /* ^P */)
+#define KEY_IS_DOWN(key) ((key) == KEY_DOWN || (key) == '+' || key == '\016' /* ^N */)
+
+/*
+ * Global variables
+ */
+#ifdef __DIALOG_MAIN__
+
+#ifdef HAVE_NCURSES
+
+/* use colors by default? */
+bool use_colors = USE_COLORS;
+
+/* shadow dialog boxes by default?
+ Note that 'use_shadow' implies 'use_colors' */
+bool use_shadow = USE_SHADOW;
+
+#endif
+
+
+/*
+ * Attribute values, default is for mono display
+ */
+chtype attributes[] = {
+ A_NORMAL, /* screen_attr */
+ A_NORMAL, /* shadow_attr */
+ A_REVERSE, /* dialog_attr */
+ A_REVERSE, /* title_attr */
+ A_REVERSE, /* border_attr */
+ A_BOLD, /* button_active_attr */
+ A_DIM, /* button_inactive_attr */
+ A_UNDERLINE, /* button_key_active_attr */
+ A_UNDERLINE, /* button_key_inactive_attr */
+ A_NORMAL, /* button_label_active_attr */
+ A_NORMAL, /* button_label_inactive_attr */
+ A_REVERSE, /* inputbox_attr */
+ A_REVERSE, /* inputbox_border_attr */
+ A_REVERSE, /* searchbox_attr */
+ A_REVERSE, /* searchbox_title_attr */
+ A_REVERSE, /* searchbox_border_attr */
+ A_REVERSE, /* position_indicator_attr */
+ A_REVERSE, /* menubox_attr */
+ A_REVERSE, /* menubox_border_attr */
+ A_REVERSE, /* item_attr */
+ A_NORMAL, /* item_selected_attr */
+ A_REVERSE, /* tag_attr */
+ A_REVERSE, /* tag_selected_attr */
+ A_NORMAL, /* tag_key_attr */
+ A_BOLD, /* tag_key_selected_attr */
+ A_REVERSE, /* check_attr */
+ A_REVERSE, /* check_selected_attr */
+ A_REVERSE, /* uarrow_attr */
+ A_REVERSE /* darrow_attr */
+};
+
+#else
+
+#ifdef HAVE_NCURSES
+extern bool use_colors;
+#endif
+
+#endif /* __DIALOG_MAIN__ */
+
+
+
+#ifdef HAVE_NCURSES
+
+/*
+ * Function prototypes
+ */
+#ifdef __DIALOG_MAIN__
+
+extern int parse_rc(void);
+
+#endif /* __DIALOG_MAIN__ */
+
+#endif
+
+
+#ifdef HAVE_NCURSES
+void color_setup(void);
+#endif
+
+void attr_clear(WINDOW *win, int height, int width, chtype attr);
+void print_autowrap(WINDOW *win, unsigned char *prompt, int height, int width, int maxwidth,
+ int y, int x, int center, int rawmode);
+void print_button(WINDOW *win, unsigned char *label, int y, int x, int selected);
+FILE *raw_popen(const char *program, char * const *argv, const char *type);
+int raw_pclose(FILE *iop);
+void display_helpfile(void);
+void display_helpline(WINDOW *w, int y, int width);
+void print_arrows(WINDOW *dialog, int scroll, int menu_height, int item_no, int box_x,
+ int box_y, int tag_x, int cur_x, int cur_y);
+
diff --git a/gnu/lib/libodialog/dir.c b/gnu/lib/libodialog/dir.c
new file mode 100644
index 0000000..5348c2f
--- /dev/null
+++ b/gnu/lib/libodialog/dir.c
@@ -0,0 +1,549 @@
+/****************************************************************************
+ *
+ * Program: dir.c
+ * Author: Marc van Kempen
+ * desc: Directory routines, sorting and reading
+ *
+ * Copyright (c) 1995, Marc van Kempen
+ *
+ * All rights reserved.
+ *
+ * This software may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ *
+ ****************************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h> /* XXX for _POSIX_VERSION ifdefs */
+
+#if !defined sgi && !defined _POSIX_VERSION
+#include <sys/dir.h>
+#endif
+#if defined __sun__
+#include <sys/dirent.h>
+#endif
+#if defined sgi || defined _POSIX_VERSION
+#include <dirent.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fnmatch.h>
+#include <sys/param.h>
+#include "dir.h"
+
+/****************************************************************************
+ *
+ * local prototypes
+ *
+ ****************************************************************************/
+
+void toggle_dotfiles(void);
+int show_dotfiles(void);
+int dir_alphasort(const void *d1, const void *d2);
+int dir_sizesort(const void *d1, const void *d2);
+int dir_datesort(const void *d1, const void *d2);
+int dir_extsort(const void *d1, const void *d2);
+
+/****************************************************************************
+ *
+ * global variables
+ *
+ ****************************************************************************/
+
+
+/* This is user-selectable, I've set them fixed for now however */
+
+void *_sort_func = dir_alphasort;
+static int _showdotfiles = TRUE;
+
+/****************************************************************************
+ *
+ * Functions
+ *
+ ****************************************************************************/
+
+int
+dir_select_nd(
+#if defined __linux__
+ const struct dirent *d
+#else
+ struct dirent *d
+#endif
+)
+/*
+ * desc: allways include a directory entry <d>, except
+ * for the current directory and other dot-files
+ * keep '..' however.
+ * pre: <d> points to a dirent
+ * post: returns TRUE if d->d_name != "." else FALSE
+ */
+{
+ if (strcmp(d->d_name, ".")==0 ||
+ (d->d_name[0] == '.' && strlen(d->d_name) > 1 && d->d_name[1] != '.')) {
+ return(FALSE);
+ } else {
+ return(TRUE);
+ }
+}/* dir_select_nd() */
+
+
+int
+dir_select(
+#ifdef __linux__
+ const struct dirent *d
+#else
+ struct dirent *d
+#endif
+)
+/*
+ * desc: allways include a directory entry <d>, except
+ * for the current directory
+ * pre: <d> points to a dirent
+ * post: returns TRUE if d->d_name != "." else FALSE
+ */
+{
+ if (strcmp(d->d_name, ".")==0) { /* don't include the current directory */
+ return(FALSE);
+ } else {
+ return(TRUE);
+ }
+} /* dir_select() */
+
+int
+dir_select_root_nd(
+#ifdef __linux__
+ const struct dirent *d
+#else
+ struct dirent *d
+#endif
+)
+/*
+ * desc: allways include a directory entry <d>, except
+ * for the current directory and the parent directory.
+ * Also skip any other dot-files.
+ * pre: <d> points to a dirent
+ * post: returns TRUE if d->d_name[0] != "." else FALSE
+ */
+{
+ if (d->d_name[0] == '.') { /* don't include the current directory */
+ return(FALSE); /* nor the parent directory */
+ } else {
+ return(TRUE);
+ }
+} /* dir_select_root_nd() */
+
+
+int
+dir_select_root(
+#ifdef __linux__
+ const struct dirent *d
+#else
+ struct dirent *d
+#endif
+)
+/*
+ * desc: allways include a directory entry <d>, except
+ * for the current directory and the parent directory
+ * pre: <d> points to a dirent
+ * post: returns TRUE if d->d_name[0] != "." else FALSE
+ */
+{
+ if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) {
+ return(FALSE);
+ } else {
+ return(TRUE);
+ }
+}/* dir_select_root() */
+
+
+#ifdef NO_ALPHA_SORT
+int
+alphasort(const void *d1, const void *d2)
+/*
+ * desc: a replacement for what should be in the library
+ */
+{
+ return(strcmp(((struct dirent *) d1)->d_name,
+ ((struct dirent *) d2)->d_name));
+} /* alphasort() */
+#endif
+
+int
+dir_alphasort(const void *d1, const void *d2)
+/*
+ * desc: compare d1 and d2, but put directories always first
+ * put '..' always on top
+ *
+ */
+{
+ DirList *f1 = ((DirList *) d1),
+ *f2 = ((DirList *) d2);
+ struct stat *s1 = &(f1->filestatus);
+ struct stat *s2 = &(f2->filestatus);
+
+ /* check for '..' */
+ if (strcmp(((DirList *) d1)->filename, "..") == 0) {
+ return(-1);
+ }
+ if (strcmp(((DirList *) d2)->filename, "..") == 0) {
+ return(1);
+ }
+
+ /* put directories first */
+ if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
+ return(strcmp(f1->filename, f2->filename));
+ };
+ if (s1->st_mode & S_IFDIR) {
+ return(-1);
+ }
+ if (s2->st_mode & S_IFDIR) {
+ return(1);
+ }
+ return(strcmp(f1->filename, f2->filename));
+
+} /* dir_alphasort() */
+
+
+int
+dir_sizesort(const void *d1, const void *d2)
+/*
+ * desc: compare d1 and d2, but put directories always first
+ *
+ */
+{
+ DirList *f1 = ((DirList *) d1),
+ *f2 = ((DirList *) d2);
+ struct stat *s1 = &(f1->filestatus);
+ struct stat *s2 = &(f2->filestatus);
+
+ /* check for '..' */
+ if (strcmp(((DirList *) d1)->filename, "..") == 0) {
+ return(-1);
+ }
+ if (strcmp(((DirList *) d2)->filename, "..") == 0) {
+ return(1);
+ }
+
+ /* put directories first */
+ if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
+ return(s1->st_size < s2->st_size ?
+ -1
+ :
+ s1->st_size >= s2->st_size);
+ };
+ if (s1->st_mode & S_IFDIR) {
+ return(-1);
+ }
+ if (s2->st_mode & S_IFDIR) {
+ return(1);
+ }
+ return(s1->st_size < s2->st_size ?
+ -1
+ :
+ s1->st_size >= s2->st_size);
+
+} /* dir_sizesort() */
+
+int
+dir_datesort(const void *d1, const void *d2)
+/*
+ * desc: compare d1 and d2 on date, but put directories always first
+ */
+{
+ DirList *f1 = ((DirList *) d1),
+ *f2 = ((DirList *) d2);
+ struct stat *s1 = &(f1->filestatus);
+ struct stat *s2 = &(f2->filestatus);
+
+
+ /* check for '..' */
+ if (strcmp(((DirList *) d1)->filename, "..") == 0) {
+ return(-1);
+ }
+ if (strcmp(((DirList *) d2)->filename, "..") == 0) {
+ return(1);
+ }
+
+ /* put directories first */
+ if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
+ return(s1->st_mtime < s2->st_mtime ?
+ -1
+ :
+ s1->st_mtime >= s2->st_mtime);
+ };
+ if (s1->st_mode & S_IFDIR) {
+ return(-1);
+ }
+ if (s2->st_mode & S_IFDIR) {
+ return(1);
+ }
+ return(s1->st_mtime < s2->st_mtime ?
+ -1
+ :
+ s1->st_mtime >= s2->st_mtime);
+
+} /* dir_datesort() */
+
+
+int
+null_strcmp(char *s1, char *s2)
+/*
+ * desc: compare strings allowing NULL pointers
+ */
+{
+ if ((s1 == NULL) && (s2 == NULL)) {
+ return(0);
+ }
+ if (s1 == NULL) {
+ return(-1);
+ }
+ if (s2 == NULL) {
+ return(1);
+ }
+ return(strcmp(s1, s2));
+} /* null_strcmp() */
+
+
+int
+dir_extsort(const void *d1, const void *d2)
+/*
+ * desc: compare d1 and d2 on extension, but put directories always first
+ * extension = "the characters after the last dot in the filename"
+ * pre: d1 and d2 are pointers to DirList type records
+ * post: see code
+ */
+{
+ DirList *f1 = ((DirList *) d1),
+ *f2 = ((DirList *) d2);
+ struct stat *s1 = &(f1->filestatus);
+ struct stat *s2 = &(f2->filestatus);
+ char *ext1, *ext2;
+ int extf, ret;
+
+
+ /* check for '..' */
+ if (strcmp(((DirList *) d1)->filename, "..") == 0) {
+ return(-1);
+ }
+ if (strcmp(((DirList *) d2)->filename, "..") == 0) {
+ return(1);
+ }
+
+
+ /* find the first extension */
+
+ ext1 = f1->filename + strlen(f1->filename);
+ extf = FALSE;
+ while (!extf && (ext1 > f1->filename)) {
+ extf = (*--ext1 == '.');
+ }
+ if (!extf) {
+ ext1 = NULL;
+ } else {
+ ext1++;
+ }
+ /* ext1 == NULL if there's no "extension" else ext1 points */
+ /* to the first character of the extension string */
+
+ /* find the second extension */
+
+ ext2 = f2->filename + strlen(f2->filename);
+ extf = FALSE;
+ while (!extf && (ext2 > f2->filename)) {
+ extf = (*--ext2 == '.');
+ }
+ if (!extf) {
+ ext2 = NULL;
+ } else {
+ ext2++;
+ }
+ /* idem as for ext1 */
+
+ if ((s1->st_mode & S_IFDIR) && (s2->st_mode & S_IFDIR)) {
+ ret = null_strcmp(ext1, ext2);
+ if (ret == 0) {
+ return(strcmp(f1->filename, f2->filename));
+ } else {
+ return(ret);
+ }
+ };
+ if (s1->st_mode & S_IFDIR) {
+ return(-1);
+ }
+ if (s2->st_mode & S_IFDIR) {
+ return(1);
+ }
+ ret = null_strcmp(ext1, ext2);
+ if (ret == 0) {
+ return(strcmp(f1->filename, f2->filename));
+ } else {
+ return(ret);
+ }
+
+} /* dir_extsort() */
+
+
+void
+get_dir(char *dirname, char *fmask, DirList **dir, int *n)
+/*
+ * desc: get the files in the current directory
+ * pre: <dir> == NULL
+ * post: <dir> contains <n> dir-entries
+ */
+{
+ char cwd[MAXPATHLEN];
+ char buf[256];
+ struct dirent **dire;
+ struct stat status;
+ int i, j, nb;
+ long d;
+
+
+ getcwd(cwd, MAXPATHLEN);
+ if (strcmp(cwd, "/") == 0) { /* we are in the root directory */
+ if (show_dotfiles()) {
+ *n = scandir(dirname, &dire, dir_select_root, alphasort);
+ } else {
+ *n = scandir(dirname, &dire, dir_select_root_nd, alphasort);
+ }
+ } else {
+ if (show_dotfiles()) {
+ *n = scandir(dirname, &dire, dir_select, alphasort);
+ } else {
+ *n = scandir(dirname, &dire, dir_select_nd, alphasort);
+ }
+ }
+
+ /* There is the possibility that we have entered a directory */
+ /* which we are not allowed to read, scandir thus returning */
+ /* -1 for *n. */
+ /* Actually I should also check for lack of memory, but I'll */
+ /* let my application happily crash if this is the case */
+ /* Solution: */
+ /* manually insert the parent directory as the only */
+ /* directory entry, and return. */
+
+ if (*n == -1) {
+ *n = 1;
+ *dir = (DirList *) malloc(sizeof(DirList));
+ strcpy((*dir)[0].filename, "..");
+ lstat("..", &status);
+ (*dir)[0].filestatus = status;
+ (*dir)[0].link = FALSE;
+ return;
+ }
+
+ *dir = (DirList *) malloc( *n * sizeof(DirList) );
+ d = 0;
+ i = 0;
+ j = 0;
+ while (j<*n) {
+ lstat(dire[j]->d_name, &status);
+ /* check if this file is to be included */
+ /* always include directories, the rest is subject to fmask */
+ if (S_ISDIR(status.st_mode)
+ || fnmatch(fmask, dire[j]->d_name, FNM_NOESCAPE) != FNM_NOMATCH) {
+ strcpy((*dir)[i].filename, dire[j]->d_name);
+ (*dir)[i].filestatus = status;
+ if ((S_IFMT & status.st_mode) == S_IFLNK) { /* handle links */
+ (*dir)[i].link = TRUE;
+ stat(dire[j]->d_name, &status);
+ nb = readlink(dire[j]->d_name, buf, sizeof(buf) - 1);
+ if (nb == -1) {
+ printf("get_dir(): Error reading link: %s\n", dire[j]->d_name);
+ exit(-1);
+ } else {
+ (*dir)[i].linkname = malloc(sizeof(char) * nb + 1);
+ strncpy((*dir)[i].linkname, buf, nb);
+ (*dir)[i].linkname[nb] = 0;
+ }
+ (*dir)[i].filestatus = status;
+ } else {
+ (*dir)[i].link = FALSE;
+ (*dir)[i].linkname = NULL;
+ }
+ i++;
+ } else {
+ /* skip this entry */
+ }
+ j++;
+ }
+ *n = i;
+
+ /* sort the directory with the directory names on top */
+ qsort((*dir), *n, sizeof(DirList), _sort_func);
+
+ /* Free the allocated memory */
+ for (i=0; i<*n; i++) {
+ free(dire[i]);
+ }
+ free(dire);
+
+ return;
+}/* get_dir() */
+
+
+void
+FreeDir(DirList *d, int n)
+/*
+ * desc: free the dirlist d
+ * pre: d != NULL
+ * post: memory allocated to d has been released
+ */
+{
+ int i;
+
+ if (d) {
+ for (i=0; i<n; i++) {
+ if (d[i].linkname) {
+ free(d[i].linkname);
+ }
+ }
+ free(d);
+ } else {
+ printf("dir.c:FreeDir(): d == NULL\n");
+ exit(-1);
+ }
+
+ return;
+} /* FreeDir() */
+
+void
+toggle_dotfiles(void)
+/*
+ * desc: toggle visibility of dot-files
+ */
+{
+ _showdotfiles = !_showdotfiles;
+
+ return;
+} /* toggle_dotfiles() */
+
+int
+show_dotfiles(void)
+/*
+ * desc: return the value of _showdotfiles
+ */
+{
+ return(_showdotfiles);
+} /* show_dotfiles() */
+
+void
+set_dotfiles(int b)
+/*
+ * desc: set the value of _showdotfiles
+ */
+{
+ _showdotfiles = b;
+
+ return;
+} /* set_dotfiles() */
diff --git a/gnu/lib/libodialog/dir.h b/gnu/lib/libodialog/dir.h
new file mode 100644
index 0000000..eadc0c5
--- /dev/null
+++ b/gnu/lib/libodialog/dir.h
@@ -0,0 +1,38 @@
+/*
+ * include file for dir.c
+ *
+ * Copyright (c) 1995, Marc van Kempen
+ *
+ * All rights reserved.
+ *
+ * This software may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/dirent.h>
+
+typedef struct DirList { /* structure to hold the directory entries */
+ char filename[MAXNAMLEN]; /* together with the stat-info per file */
+ struct stat filestatus; /* filename, or the name to which it points */
+ int link; /* is it a link ? */
+ char *linkname; /* the name of the file the link points to */
+} DirList;
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+void get_dir(char *dirname, char *fmask, DirList **dir, int *n);
+void get_filenames(DirList *d, int n, char ***names, int *nf);
+void FreeDir(DirList *d, int n);
diff --git a/gnu/lib/libodialog/fselect.c b/gnu/lib/libodialog/fselect.c
new file mode 100644
index 0000000..6669edc
--- /dev/null
+++ b/gnu/lib/libodialog/fselect.c
@@ -0,0 +1,402 @@
+/*
+ * program: fselect.c
+ * author: Marc van Kempen (wmbfmk@urc.tue.nl)
+ * Desc: File selection routine
+ *
+ * Copyright (c) 1995, Marc van Kempen
+ *
+ * All rights reserved.
+ *
+ * This software may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <dialog.h>
+#include "ui_objects.h"
+#include "dir.h"
+#include "dialog.priv.h"
+
+/*
+ * Local prototypes
+ */
+
+char *dialog_dfselect(char *dir, char *fmask, int is_fselect);
+
+/*
+ * Functions
+ */
+
+void
+get_directories(DirList *d, int n, char ***names, int *nd)
+/*
+ * Desc: return the directorienames in <dir> as an array in
+ * <names>, the # of entries in <nd>, memory allocated
+ * to *names should be freed when done with it.
+ */
+{
+ int i;
+
+ /* count the directories, which are in front */
+ *nd = 0;
+ while ((*nd < n) && (S_ISDIR(d[*nd].filestatus.st_mode))) (*nd)++;
+ *names = (char **) malloc( *nd * sizeof(char *) );
+ for (i=0; i<*nd; i++) {
+ (*names)[i] = (char *) malloc( strlen(d[i].filename) + 1);
+ strcpy((*names)[i], d[i].filename);
+ }
+
+ return;
+} /* get_directories() */
+
+void
+get_filenames(DirList *d, int n, char ***names, int *nf)
+/*
+ * Desc: return the filenames in <dir> as an arry in
+ * <names>, the # of entries in <nf>, memory allocated
+ * to *names should be freed when done.
+ */
+{
+ int nd, i;
+
+ /* the # of regular files is the total # of files - # of directories */
+ /* count the # of directories */
+ nd = 0;
+ while ((nd < n) && (S_ISDIR(d[nd].filestatus.st_mode))) nd++;
+
+ *names = (char **) malloc( (n-nd) * sizeof(char *) );
+ *nf = n - nd;
+ for (i=0; i<*nf; i++) {
+ (*names)[i] = (char *) malloc( strlen(d[i+nd].filename) + 1);
+ strcpy((*names)[i], d[i+nd].filename);
+ }
+
+ return;
+} /* get_filenames() */
+
+void
+FreeNames(char **names, int n)
+/*
+ * Desc: free the space occupied by names
+ */
+{
+ int i;
+
+ /* free the space occupied by names */
+ for (i=0; i<n; i++) {
+ free(names[i]);
+ }
+ free(names);
+
+ return;
+} /* FreeNames() */
+
+int
+dialog_dselect_old(void)
+/*
+ * Desc: starting from the current directory,
+ * choose a new current directory
+ */
+{
+ DirList *d = NULL;
+ char **names, old_dir[MAXPATHLEN];
+ WINDOW *ds_win;
+ ButtonObj *okbut, *cancelbut;
+ ListObj *dirs_obj;
+ StringObj *dir_obj;
+ char o_dir[MAXPATHLEN];
+ struct ComposeObj *obj = NULL;
+ int n, nd, okbutton, cancelbutton,
+ quit, cancel, ret;
+
+ ds_win = newwin(LINES-8, COLS-30, 4, 15);
+ if (ds_win == NULL) {
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n",
+ LINES-8, COLS-30, 4, 15);
+ exit(1);
+ }
+ draw_box(ds_win, 0, 0, LINES-8, COLS-30, dialog_attr, border_attr);
+ wattrset(ds_win, dialog_attr);
+ mvwaddstr(ds_win, 0, (COLS-30)/2 - 9, " Directory Select ");
+ draw_shadow(stdscr, 4, 15, LINES-8, COLS-30);
+ display_helpline(ds_win, LINES-9, COLS-30);
+
+ /* the Directory string input field */
+ getcwd(o_dir, MAXPATHLEN);
+ dir_obj = NewStringObj(ds_win, "Directory:", o_dir, 1, 2, COLS-34, MAXPATHLEN-1);
+ AddObj(&obj, STRINGOBJ, (void *) dir_obj);
+
+ /* the list of directories */
+ get_dir(".", "*", &d, &n);
+ get_directories(d, n, &names, &nd);
+ dirs_obj = NewListObj(ds_win, "Directories:", names, o_dir, 5, 2,
+ LINES-15, COLS-48, nd);
+ AddObj(&obj, LISTOBJ, (void *) dirs_obj);
+
+ /* the Ok-button */
+ okbutton = FALSE;
+ okbut = NewButtonObj(ds_win, "Continue", &okbutton, 7, COLS-45);
+ AddObj(&obj, BUTTONOBJ, (void *) okbut);
+
+ /* the Cancel-button */
+ cancelbutton = FALSE;
+ cancelbut = NewButtonObj(ds_win, "Return", &cancelbutton, 11, COLS-44);
+ AddObj(&obj, BUTTONOBJ, (void *) cancelbut);
+
+ quit = FALSE;
+ cancel = FALSE;
+ strcpy(old_dir, o_dir);
+ while (!quit) {
+ ret = PollObj(&obj);
+ switch(ret) {
+ case SEL_BUTTON:
+ if (okbutton) {
+ quit = TRUE;
+ }
+ if (cancelbutton) {
+ quit = TRUE;
+ cancel = TRUE;
+ }
+ break;
+ case SEL_CR:
+ if (strcmp(old_dir, o_dir)) {
+ /* the directory was changed, cd into it */
+ if (chdir(o_dir)) {
+ dialog_notify("Could not change into directory");
+ strcpy(o_dir, old_dir);
+ } else {
+ getcwd(o_dir, MAXPATHLEN);
+ strcpy(old_dir, o_dir);
+ }
+ RefreshStringObj(dir_obj);
+ }
+ get_dir(".", "*", &d, &n);
+ FreeNames(names, nd);
+ get_directories(d, n, &names, &nd);
+ UpdateListObj(dirs_obj, names, nd);
+ if (((obj->prev)->obj == (void *) dirs_obj)) {
+ obj=obj->prev;
+ }
+ break;
+ case SEL_ESC:
+ quit = TRUE;
+ cancel = TRUE;
+ break;
+ case KEY_F(1):
+ display_helpfile();
+ break;
+ }
+ }
+
+ FreeNames(names, nd);
+ DelObj(obj);
+ delwin(ds_win);
+
+ return(cancel);
+
+} /* dialog_dselect() */
+
+int
+dialog_dselect(char *dir, char *fmask)
+/*
+ * Desc: Choose a directory
+ */
+{
+ if (dialog_dfselect(dir, fmask, FALSE)) {
+ return(FALSE); /* esc or cancel was pressed */
+ } else {
+ return(TRUE); /* directory was selected */
+ }
+} /* dialog_dselect() */
+
+char *
+dialog_fselect(char *dir, char *fmask)
+/*
+ * Desc: Choose a file from a directory
+ */
+{
+ return(dialog_dfselect(dir, fmask, TRUE));
+} /* dialog_fselect() */
+
+char *
+dialog_dfselect(char *dir, char *fmask, int is_fselect)
+/*
+ * Desc: choose a file from the directory <dir>, which
+ * initially display files with the mask <filemask>
+ * pre: <dir> is the initial directory
+ * only files corresponding to the mask <fmask> are displayed
+ * post: returns NULL if no file was selected
+ * else returns pointer to filename, space is allocated, should
+ * be freed after use.
+ */
+{
+ DirList *d = NULL;
+ char msg[512];
+ char **fnames, **dnames, *ret_name;
+ WINDOW *fs_win;
+ int n, nd, nf, ret;
+ StringObj *fm_obj, *dir_obj, *sel_obj;
+ char o_fm[255], o_dir[MAXPATHLEN], o_sel[MAXPATHLEN];
+ char old_fmask[255], old_dir[MAXPATHLEN];
+ ListObj *dirs_obj, *files_obj;
+ struct ComposeObj *obj = NULL, *o;
+ int quit, cancel;
+ ButtonObj *okbut_obj, *canbut_obj;
+ int ok_button, cancel_button;
+
+ if (chdir(dir)) {
+ sprintf(msg, "Could not move into specified directory: %s", dir);
+ dialog_notify(msg);
+ return(NULL);
+ }
+ getcwd(o_dir, MAXPATHLEN);
+
+ /* setup the fileselect-window and initialize its components */
+ fs_win = newwin(LINES-2, COLS-20, 1, 10);
+ if (fs_win == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n",
+ LINES-2, COLS-20, 2, 10);
+ exit(1);
+ }
+ draw_box(fs_win, 0, 0, LINES-2, COLS-20, dialog_attr, border_attr);
+ wattrset(fs_win, dialog_attr);
+ if (is_fselect) {
+ mvwaddstr(fs_win, 0, (COLS-20)/2 - 7, " File Select ");
+ } else {
+ mvwaddstr(fs_win, 0, (COLS-20)/2 - 9, " Directory Select ");
+ }
+ draw_shadow(stdscr, 1, 10, LINES-2, COLS-20);
+ display_helpline(fs_win, LINES-3, COLS-20);
+
+ /* Filemask entry */
+ strcpy(o_fm, fmask);
+ fm_obj = NewStringObj(fs_win, "Filemask:", o_fm, 1, 2, 19, 255);
+ AddObj(&obj, STRINGOBJ, (void *) fm_obj);
+
+ /* Directory entry */
+ dir_obj = NewStringObj(fs_win, "Directory:", o_dir, 1, 22, COLS-44, 255);
+ AddObj(&obj, STRINGOBJ, (void *) dir_obj);
+
+ /* Directory list */
+ get_dir(".", fmask, &d, &n); /* read the entire directory */
+ get_directories(d, n, &dnames, &nd); /* extract the dir-entries */
+ if (is_fselect) {
+ dirs_obj = NewListObj(fs_win, "Directories:", dnames, o_dir, 5, 2,
+ LINES-16, (COLS-20)/2-2, nd);
+ } else {
+ dirs_obj = NewListObj(fs_win, "Directories:", dnames, o_dir, 5, 2,
+ LINES-12, (COLS-20)/2-2, nd);
+ }
+ AddObj(&obj, LISTOBJ, (void *) dirs_obj);
+
+ /* Filenames list */
+ get_filenames(d, n, &fnames, &nf); /* extract the filenames */
+ if (is_fselect) {
+ files_obj = NewListObj(fs_win, "Files:", fnames, o_sel, 5, (COLS-20)/2+1,
+ LINES-16, (COLS-20)/2-3, nf);
+ } else {
+ files_obj = NewListObj(fs_win, "Files:", fnames, o_sel, 5, (COLS-20)/2+1,
+ LINES-12, (COLS-20)/2-3, nf);
+ }
+ AddObj(&obj, LISTOBJ, (void *) files_obj);
+
+ if (is_fselect) {
+ /* Selection entry */
+ o_sel[0] = '\0';
+ sel_obj = NewStringObj(fs_win, "Selection:", o_sel, LINES-10, 2, COLS-24, 255);
+ AddObj(&obj, STRINGOBJ, (void *) sel_obj);
+ }
+
+ /* Ok button */
+ ok_button = FALSE;
+ okbut_obj = NewButtonObj(fs_win, "Ok", &ok_button, LINES-6, 20);
+ AddObj(&obj, BUTTONOBJ, (void *) okbut_obj);
+
+ /* Cancel button */
+ cancel_button = FALSE;
+ canbut_obj = NewButtonObj(fs_win, "Cancel", &cancel_button, LINES-6, 30);
+ AddObj(&obj, BUTTONOBJ, (void *) canbut_obj);
+
+ /* Make sure all objects on the window are drawn */
+ wrefresh(fs_win);
+ keypad(fs_win, TRUE);
+
+ /* Start the reading */
+ o = obj;
+ strcpy(old_fmask, o_fm);
+ strcpy(old_dir, o_dir);
+ quit = FALSE;
+ cancel = FALSE;
+ while (!quit) {
+ ret = PollObj(&o);
+ switch(ret) {
+ case SEL_CR:
+ if (strcmp(old_fmask, o_fm) || strcmp(old_dir, o_dir)) {
+ /* reread directory and update the listobjects */
+ if (strcmp(old_dir, o_dir)) { /* dir entry was changed */
+ if (chdir(o_dir)) {
+ dialog_notify("Could not change into directory");
+ strcpy(o_dir, old_dir);
+ } else {
+ getcwd(o_dir, MAXPATHLEN);
+ strcpy(old_dir, o_dir);
+ }
+ RefreshStringObj(dir_obj);
+ } else { /* fmask entry was changed */
+ strcpy(old_fmask, o_fm);
+ }
+ get_dir(".", o_fm, &d, &n);
+ FreeNames(dnames, nd);
+ get_directories(d, n, &dnames, &nd);
+ UpdateListObj(dirs_obj, dnames, nd);
+ FreeNames(fnames, nf);
+ get_filenames(d, n, &fnames, &nf);
+ UpdateListObj(files_obj, fnames, nf);
+ if (((o->prev)->obj == (void *) dirs_obj)) {
+ o=o->prev;
+ }
+ }
+ break;
+ case SEL_BUTTON:
+ /* check which button was pressed */
+ if (ok_button) {
+ quit = TRUE;
+ }
+ if (cancel_button) {
+ quit = TRUE;
+ cancel = TRUE;
+ }
+ break;
+ case SEL_ESC:
+ quit = TRUE;
+ cancel = TRUE;
+ break;
+ case KEY_F(1):
+ case '?':
+ display_helpfile();
+ break;
+ }
+ }
+ DelObj(obj);
+ FreeNames(dnames, nd);
+ FreeNames(fnames, nf);
+ delwin(fs_win);
+
+ if (cancel || (strlen(o_sel) == 0)) {
+ return(NULL);
+ } else {
+ ret_name = (char *) malloc( strlen(o_sel) + 1 );
+ strcpy(ret_name, o_sel);
+ return(ret_name);
+ }
+} /* dialog_fselect() */
+
diff --git a/gnu/lib/libodialog/gauge.c b/gnu/lib/libodialog/gauge.c
new file mode 100644
index 0000000..d8138f6
--- /dev/null
+++ b/gnu/lib/libodialog/gauge.c
@@ -0,0 +1,79 @@
+/*
+ * gauge.c
+ *
+ * progress indicator for libdialog
+ *
+ *
+ * Copyright (c) 1995, Marc van Kempen
+ *
+ * All rights reserved.
+ *
+ * This software may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dialog.h"
+
+void
+dialog_gauge(char *title, char *prompt, int y, int x,
+ int height, int width, int perc)
+/*
+ * Desc: display a progress bar, progress indicated by <perc>
+ */
+{
+ WINDOW *gw;
+ int glen, i;
+ char percs[5];
+
+ gw = newwin(height, width, y, x);
+ if (!gw) {
+ fprintf(stderr, "dialog_gauge: Error creating window (%d, %d, %d, %d)",
+ height, width, y, x);
+ exit(-1);
+ }
+
+ draw_box(gw, 0, 0, height, width, dialog_attr, border_attr);
+ draw_shadow(stdscr, y, x, height, width);
+
+ wattrset(gw, title_attr);
+ if (title) {
+ wmove(gw, 0, (width - strlen(title))/2 - 1);
+ waddstr(gw, "[ ");
+ waddstr(gw, title);
+ waddstr(gw, " ]");
+ }
+ wattrset(gw, dialog_attr);
+ if (prompt) {
+ wmove(gw, 1, (width - strlen(prompt))/2 - 1);
+ waddstr(gw, prompt);
+ }
+
+ draw_box(gw, 2, 2, 3, width-4, dialog_attr, border_attr);
+ glen = (int) ((float) perc/100 * (width-6));
+
+ wattrset(gw, dialog_attr);
+ sprintf(percs, "%3d%%", perc);
+ wmove(gw, 5, width/2 - 2);
+ waddstr(gw, percs);
+
+ wattrset(gw, A_BOLD);
+ wmove(gw, 3, 3);
+ for (i=0; i<glen; i++) waddch(gw, ' ');
+
+ wrefresh(gw);
+ delwin(gw);
+
+ return;
+} /* dialog_gauge() */
+
diff --git a/gnu/lib/libodialog/help.c b/gnu/lib/libodialog/help.c
new file mode 100644
index 0000000..de49c6a
--- /dev/null
+++ b/gnu/lib/libodialog/help.c
@@ -0,0 +1,194 @@
+/***************************************************************
+ *
+ * Program: help.c
+ * Author: Marc van Kempen
+ * Desc: get help
+ *
+ *
+ * Copyright (c) 1995, Marc van Kempen
+ *
+ * All rights reserved.
+ *
+ * This software may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ *
+ ***************************************************************/
+
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <dialog.h>
+
+static char _helpfilebuf[MAXPATHLEN];
+static char _helplinebuf[77]; /* limit the helpline to 76 characters */
+static char *_helpfile = NULL;
+static char *_helpline = NULL;
+
+/******************************************************************
+ *
+ * helpfile routines
+ *
+ ******************************************************************/
+
+void
+use_helpfile(char *hfile)
+/*
+ * desc: set the helpfile to be opened on pressing F1 to <helpfile>
+ */
+{
+ if (hfile != NULL) {
+ _helpfile = _helpfilebuf;
+ strcpy(_helpfile, hfile);
+ } else {
+ _helpfile = NULL;
+ }
+
+ return;
+} /* use_helpfile() */
+
+void
+display_helpfile(void)
+/*
+ * desc: display the current helpfile in a window
+ */
+{
+ WINDOW *w;
+ FILE *f;
+ struct stat sb;
+ char msg[80], *buf;
+ static int in_help = FALSE;
+ char *savehline = NULL;
+
+ if (in_help) return; /* dont call help when you're in help */
+
+ if (_helpfile != NULL) {
+ if ((w = dupwin(newscr)) == NULL) {
+ dialog_notify("No memory to dup previous screen\n");
+ return;
+ }
+ if ((f = fopen(_helpfile, "r")) == NULL) {
+ sprintf(msg, "Can't open helpfile : %s\n", _helpfile);
+ dialog_notify(msg);
+ return;
+ }
+ if (fstat(fileno(f), &sb)) {
+ sprintf(msg, "Can't stat helpfile : %s\n", _helpfile);
+ dialog_notify(msg);
+ return;
+ }
+ if ((buf = (char *) malloc( sb.st_size )) == NULL) {
+ sprintf(msg, "Could not malloc space for helpfile : %s\n", _helpfile);
+ dialog_notify(msg);
+ return;
+ }
+ if (fread(buf, 1, sb.st_size, f) != sb.st_size) {
+ sprintf(msg, "Could not read entire help file : %s", _helpfile);
+ dialog_notify(msg);
+ free(buf);
+ return;
+ }
+ buf[sb.st_size] = 0;
+ in_help = TRUE;
+ savehline = get_helpline();
+ use_helpline("Use arrowkeys, PgUp, PgDn, Home and End to move through text");
+ dialog_mesgbox("Online help", buf, LINES-4, COLS-4);
+ restore_helpline(savehline);
+ in_help = FALSE;
+ touchwin(w);
+ wrefresh(w);
+ delwin(w);
+ free(buf);
+ } else {
+ /* do nothing */
+ }
+
+ return;
+} /* display_helpfile() */
+
+
+/******************************************************************
+ *
+ * helpline routines
+ *
+ ******************************************************************/
+
+void
+use_helpline(char *hline)
+/*
+ * desc: set the helpline to printed in dialogs
+ */
+{
+ if (hline) {
+ _helpline = _helplinebuf;
+ if (strlen(hline) > 76) {
+ /* only display the first 76 characters in the helpline */
+ strncpy(_helpline, hline, 76);
+ _helpline[76] = 0;
+ } else {
+ strcpy(_helpline, hline);
+ }
+ } else {
+ _helpline = NULL;
+ }
+
+ return;
+} /* use_helpline() */
+
+void
+display_helpline(WINDOW *w, int y, int width)
+/*
+ * desc: display the helpline at the given coordinates <y, x> in the window <w>
+ */
+{
+ if (_helpline != NULL) {
+ if (strlen(_helpline) > width - 6) {
+ _helpline[width - 6] = 0;
+ }
+ wmove(w, y, (int) (width - strlen(_helpline)- 4) / 2);
+ wattrset(w, title_attr);
+ waddstr(w, "[ ");
+ waddstr(w, _helpline);
+ waddstr(w, " ]");
+ } else {
+ /* do nothing */
+ }
+
+ return;
+}
+
+char *
+get_helpline(void)
+/*
+ * desc: allocate new space, copy the helpline to it and return a pointer to it
+ */
+{
+ char *hlp;
+
+ if (_helpline) {
+ hlp = (char *) malloc( strlen(_helpline) + 1 );
+ strcpy(hlp, _helpline);
+ } else {
+ hlp = NULL;
+ }
+
+ return(hlp);
+} /* get_helpline() */
+
+void
+restore_helpline(char *helpline)
+/*
+ * Desc: set the helpline to <helpline> and free the space allocated to it
+ */
+{
+ use_helpline(helpline);
+ free(helpline);
+
+ return;
+} /* restore_helpline() */
diff --git a/gnu/lib/libodialog/inputbox.c b/gnu/lib/libodialog/inputbox.c
new file mode 100644
index 0000000..1f61ed5
--- /dev/null
+++ b/gnu/lib/libodialog/inputbox.c
@@ -0,0 +1,190 @@
+/*
+ * inputbox.c -- implements the input box
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <dialog.h>
+#include "dialog.priv.h"
+
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int dialog_inputbox(unsigned char *title, unsigned char *prompt, int height, int width, unsigned char *result)
+{
+ int i, j, x, y, box_y, box_x, box_width, first,
+ key = 0, button = -1;
+ unsigned char instr[MAX_LEN+1];
+ WINDOW *dialog;
+
+ if (height < 0)
+ height = strheight(prompt)+2+4;
+ if (width < 0) {
+ i = strwidth(prompt);
+ j = ((title != NULL) ? strwidth(title) : 0);
+ width = MAX(i,j) + 4;
+ }
+ width = MAX(width,24);
+
+ if (width > COLS)
+ width = COLS;
+ if (height > LINES)
+ height = LINES;
+ /* center dialog box on screen */
+ x = DialogX ? DialogX : (COLS - width)/2;
+ y = DialogY ? DialogY : (LINES - height)/2;
+
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(stdscr, y, x, height, width);
+#endif
+ dialog = newwin(height, width, y, x);
+ if (dialog == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width,y,x);
+ exit(1);
+ }
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+ wattrset(dialog, border_attr);
+ wmove(dialog, height-3, 0);
+ waddch(dialog, ACS_LTEE);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dialog_attr);
+ waddch(dialog, ACS_RTEE);
+ wmove(dialog, height-2, 1);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ' ');
+
+ if (title != NULL) {
+ wattrset(dialog, title_attr);
+ wmove(dialog, 0, (width - strlen(title))/2 - 1);
+ waddch(dialog, ' ');
+ waddstr(dialog, title);
+ waddch(dialog, ' ');
+ }
+ wattrset(dialog, dialog_attr);
+ wmove(dialog, 1, 2);
+ print_autowrap(dialog, prompt, height-1, width-2, width, 1, 2, TRUE, FALSE);
+
+ /* Draw the input field box */
+ box_width = width-6;
+ getyx(dialog, y, x);
+ box_y = y + 2;
+ box_x = (width - box_width)/2;
+ draw_box(dialog, y+1, box_x-1, 3, box_width+2, border_attr, dialog_attr);
+
+ display_helpline(dialog, height-1, width);
+
+ x = width/2-11;
+ y = height-2;
+ print_button(dialog, "Cancel", y, x+14, FALSE);
+ print_button(dialog, " OK ", y, x, TRUE);
+
+ first = 1;
+ strcpy(instr, result);
+ wattrset(dialog, dialog_attr);
+
+ while (key != ESC) {
+
+ if (button == -1) { /* Input box selected */
+ key = line_edit(dialog, box_y, box_x, -1, box_width, inputbox_attr, first, instr, DialogInputAttrs);
+ first = 0;
+ }
+ else
+ key = wgetch(dialog);
+
+ switch (key) {
+ case 'O':
+ case 'o':
+ delwin(dialog);
+ strcpy(result, instr);
+ return 0;
+ case 'C':
+ case 'c':
+ delwin(dialog);
+ return 1;
+ case KEY_UP:
+ case KEY_LEFT:
+ case KEY_BTAB:
+ switch (button) {
+ case -1:
+ button = 1; /* Indicates "Cancel" button is selected */
+ print_button(dialog, " OK ", y, x, FALSE);
+ print_button(dialog, "Cancel", y, x+14, TRUE);
+ wrefresh(dialog);
+ break;
+ case 0:
+ button = -1; /* Indicates input box is selected */
+ print_button(dialog, "Cancel", y, x+14, FALSE);
+ print_button(dialog, " OK ", y, x, TRUE);
+ break;
+ case 1:
+ button = 0; /* Indicates "OK" button is selected */
+ print_button(dialog, "Cancel", y, x+14, FALSE);
+ print_button(dialog, " OK ", y, x, TRUE);
+ wrefresh(dialog);
+ break;
+ }
+ break;
+ case TAB:
+ case KEY_DOWN:
+ case KEY_RIGHT:
+ switch (button) {
+ case -1:
+ button = 0; /* Indicates "OK" button is selected */
+ print_button(dialog, "Cancel", y, x+14, FALSE);
+ print_button(dialog, " OK ", y, x, TRUE);
+ wrefresh(dialog);
+ break;
+ case 0:
+ button = 1; /* Indicates "Cancel" button is selected */
+ print_button(dialog, " OK ", y, x, FALSE);
+ print_button(dialog, "Cancel", y, x+14, TRUE);
+ wrefresh(dialog);
+ break;
+ case 1:
+ button = -1; /* Indicates input box is selected */
+ print_button(dialog, "Cancel", y, x+14, FALSE);
+ print_button(dialog, " OK ", y, x, TRUE);
+ break;
+ }
+ break;
+ case ' ':
+ case '\n':
+ case '\r':
+ delwin(dialog);
+ if (button < 1)
+ strcpy(result, instr);
+ return (button == -1 ? 0 : button);
+ case ESC:
+ break;
+ case KEY_F(1):
+ case '?':
+ display_helpfile();
+ break;
+ }
+ }
+
+ delwin(dialog);
+ return -1; /* ESC pressed */
+}
+/* End of dialog_inputbox() */
diff --git a/gnu/lib/libodialog/kernel.c b/gnu/lib/libodialog/kernel.c
new file mode 100644
index 0000000..9ed5eac
--- /dev/null
+++ b/gnu/lib/libodialog/kernel.c
@@ -0,0 +1,536 @@
+/*
+ * dialog - Display simple dialog boxes from shell scripts
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * HISTORY:
+ *
+ * 17/12/93 - Version 0.1 released.
+ *
+ * 19/12/93 - menu will now scroll if there are more items than can fit
+ * on the screen.
+ * - added 'checklist', a dialog box with a list of options that
+ * can be turned on or off. A list of options that are on is
+ * returned on exit.
+ *
+ * 20/12/93 - Version 0.15 released.
+ *
+ * 29/12/93 - Incorporated patch from Patrick J. Volkerding
+ * (volkerdi@mhd1.moorhead.msus.edu) that made these changes:
+ * - increased MAX_LEN to 2048
+ * - added 'infobox', equivalent to a message box without pausing
+ * - added option '--clear' that will clear the screen
+ * - Explicit line breaking when printing prompt text can be
+ * invoked by real newline '\n' besides the string "\n"
+ * - an optional parameter '--title <string>' can be used to
+ * specify a title string for the dialog box
+ *
+ * 03/01/94 - added 'textbox', a dialog box for displaying text from a file.
+ * - Version 0.2 released.
+ *
+ * 04/01/94 - some fixes and improvements for 'textbox':
+ * - fixed a bug that will cause a segmentation violation when a
+ * line is longer than MAX_LEN characters. Lines will now be
+ * truncated if they are longer than MAX_LEN characters.
+ * - removed wrefresh() from print_line(). This will increase
+ * efficiency of print_page() which calls print_line().
+ * - display current position in the form of percentage into file.
+ * - Version 0.21 released.
+ *
+ * 05/01/94 - some changes for faster screen update.
+ *
+ * 07/01/94 - much more flexible color settings. Can use all 16 colors
+ * (8 normal, 8 highlight) of the Linux console.
+ *
+ * 08/01/94 - added run-time configuration using configuration file.
+ *
+ * 09/01/94 - some minor bug fixes and cleanups for menubox, checklist and
+ * textbox.
+ *
+ * 11/01/94 - added a man page.
+ *
+ * 13/01/94 - some changes for easier porting to other Unix systems (tested
+ * on Ultrix, SunOS and HPUX)
+ * - Version 0.3 released.
+ *
+ * 08/06/94 - Patches by Stuart Herbert - S.Herbert@shef.ac.uk
+ * Fixed attr_clear and the textbox stuff to work with ncurses 1.8.5
+ * Fixed the wordwrap routine - it'll actually wrap properly now
+ * Added a more 3D look to everything - having your own rc file could
+ * prove 'interesting' to say the least :-)
+ * Added radiolist option
+ * - Version 0.4 released.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define __DIALOG_MAIN__
+
+#include <dialog.h>
+#include <err.h>
+#include "dialog.priv.h"
+#ifdef HAVE_NCURSES
+#include "colors.h"
+#endif
+
+/* These are two "secret" globals that can be fiddled to make a dialog
+ * come up someplace other than a "centered" calculation for X,Y
+ */
+int DialogX, DialogY;
+
+/* This "secret" global allows you to change the behavior of an input field */
+int DialogInputAttrs;
+
+/*
+ * Do some initialization for dialog
+ */
+void init_dialog(void)
+{
+
+ if (issetugid()) {
+ errx(1, "libdialog is unsafe to use in setugid applications");
+ }
+
+#if defined(LOCALE)
+ (void) setlocale(LC_ALL, "");
+#endif
+
+#ifdef HAVE_NCURSES
+ if (parse_rc() == -1) /* Read the configuration file */
+ exit(-1);
+#endif
+
+ if (initscr() == NULL) { /* Init curses */
+ fprintf(stderr, "\nCurses initialization error.\n");
+ exit(-1);
+ }
+ keypad(stdscr, TRUE);
+ cbreak();
+ noecho();
+
+#ifdef HAVE_NCURSES
+ if (use_colors || use_shadow) /* Set up colors */
+ color_setup();
+#endif
+
+ /* Set screen to screen attribute */
+ dialog_clear_norefresh();
+ DialogX = DialogY = 0;
+}
+/* End of init_dialog() */
+
+
+#ifdef HAVE_NCURSES
+/*
+ * Setup for color display
+ */
+void color_setup(void)
+{
+ int i;
+
+ if (has_colors()) { /* Terminal supports color? */
+ start_color();
+
+ /* Initialize color pairs */
+ for (i = 0; i < ATTRIBUTE_COUNT; i++)
+ init_pair(i+1, color_table[i][0], color_table[i][1]);
+
+ /* Setup color attributes */
+ for (i = 0; i < ATTRIBUTE_COUNT; i++)
+ attributes[i] = C_ATTR(color_table[i][2], i+1);
+ }
+}
+/* End of color_setup() */
+#endif
+
+
+/*
+ * Set window to attribute 'attr'
+ */
+void attr_clear(WINDOW *win, int height, int width, chtype attr)
+{
+ int i, j;
+
+ wattrset(win, attr); /* Set window to attribute 'attr' */
+ for (i = 0; i < height; i++) {
+ wmove(win, i, 0);
+ for (j = 0; j < width; j++)
+ waddch(win, ' ');
+ }
+}
+/* End of attr_clear() */
+
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Note that the
+ * string may contain "\n" to represent a newline character or the real
+ * newline '\n', but in that case, auto wrap around will be disabled.
+ */
+void print_autowrap(WINDOW *win, unsigned char *prompt, int height, int width, int maxwidth, int y, int x, int center, int rawmode)
+{
+ int cur_x, cur_y, i;
+ unsigned char tempstr[MAX_LEN+1], *word, *tempptr, *tempptr1;
+ chtype ostuff[132], attrs = 0, init_bottom = 0;
+
+ wsetscrreg(win, y, height);
+ getyx(win, cur_y, cur_x);
+
+ strncpy(tempstr, prompt, MAX_LEN);
+ tempstr[MAX_LEN] = '\0';
+ if ((!rawmode && strstr(tempstr, "\\n") != NULL) ||
+ (strchr(tempstr, '\n') != NULL)) { /* Prompt contains "\n" or '\n' */
+ word = tempstr;
+ while (1) {
+ tempptr = rawmode ? NULL : strstr(word, "\\n");
+ tempptr1 = strchr(word, '\n');
+ if (tempptr == NULL && tempptr1 == NULL)
+ break;
+ else if (tempptr == NULL) { /* No more "\n" */
+ tempptr = tempptr1;
+ tempptr[0] = '\0';
+ }
+ else if (tempptr1 == NULL) { /* No more '\n' */
+ tempptr[0] = '\0';
+ tempptr++;
+ }
+ else { /* Prompt contains both "\n" and '\n' */
+ if (strlen(tempptr)-2 < strlen(tempptr1)-1) {
+ tempptr = tempptr1;
+ tempptr[0] = '\0';
+ }
+ else {
+ tempptr[0] = '\0';
+ tempptr++;
+ }
+ }
+
+ waddstr(win, word);
+ word = tempptr + 1;
+ if (++cur_y > height) {
+ cur_y--;
+ if (!init_bottom) {
+ for (i = 0; i < x; i++)
+ ostuff[i] = mvwinch(win, cur_y, i);
+ for (i = width; i < maxwidth; i++)
+ ostuff[i] = mvwinch(win, cur_y, i);
+ attrs = getattrs(win);
+ init_bottom = 1;
+ }
+ scrollok(win, TRUE);
+ scroll(win);
+ scrollok(win, FALSE);
+ wmove(win, cur_y, 0);
+ for (i = 0; i < x; i++) {
+ wattrset(win, ostuff[i]&A_ATTRIBUTES);
+ waddch(win, ostuff[i]);
+ }
+ wattrset(win, attrs);
+ for ( ; i < width; i++)
+ waddch(win, ' ');
+ for ( ; i < maxwidth; i++) {
+ wattrset(win, ostuff[i]&A_ATTRIBUTES);
+ waddch(win, ostuff[i]);
+ }
+ wattrset(win, attrs);
+ wrefresh(win);
+ }
+ wmove(win, cur_y, cur_x = x);
+ }
+ waddstr(win, word);
+ }
+ else if (center && strlen(tempstr) <= width-x*2) { /* If prompt is short */
+ wmove(win, cur_y, (width - strlen(tempstr)) / 2);
+ waddstr(win, tempstr);
+ }
+ else if (!center && strlen(tempstr) <= width-cur_x) { /* If prompt is short */
+ waddstr(win, tempstr);
+ }
+ else {
+ char *p = tempstr;
+
+ /* Print prompt word by word, wrap around if necessary */
+ while ((word = strsep(&p, "\t\n ")) != NULL) {
+ int loop;
+ unsigned char sc;
+
+ if (*word == '\0')
+ continue;
+ do {
+ loop = 0;
+ if (cur_x+strlen(word) >= width+1) { /* wrap around to next line */
+ if (x+strlen(word) >= width+1) {
+ sc = word[width-cur_x-1];
+ word[width-cur_x-1] = '\0';
+ wmove(win, cur_y, cur_x);
+ waddstr(win, word);
+ word[width-cur_x-1] = sc;
+ word += width-cur_x-1;
+ getyx(win, cur_y, cur_x);
+ loop = 1;
+ }
+ cur_y++;
+ cur_x = x;
+ if (cur_y > height) {
+ cur_y--;
+ if (!init_bottom) {
+ for (i = 0; i < x; i++)
+ ostuff[i] = mvwinch(win, cur_y, i);
+ for (i = width; i < maxwidth; i++)
+ ostuff[i] = mvwinch(win, cur_y, i);
+ attrs = getattrs(win);
+ init_bottom = 1;
+ }
+ scrollok(win, TRUE);
+ scroll(win);
+ scrollok(win, FALSE);
+ wmove(win, cur_y, 0);
+ for (i = 0; i < x; i++) {
+ wattrset(win, ostuff[i]&A_ATTRIBUTES);
+ waddch(win, ostuff[i]);
+ }
+ wattrset(win, attrs);
+ for ( ; i < width; i++)
+ waddch(win, ' ');
+ for ( ; i < maxwidth; i++) {
+ wattrset(win, ostuff[i]&A_ATTRIBUTES);
+ waddch(win, ostuff[i]);
+ }
+ wattrset(win, attrs);
+ wrefresh(win);
+ }
+ }
+ }
+ while(loop);
+ wmove(win, cur_y, cur_x);
+ waddstr(win, word);
+ getyx(win, cur_y, cur_x);
+ cur_x++;
+ }
+ }
+}
+/* End of print_autowrap() */
+
+
+/*
+ * Print a button
+ */
+void print_button(WINDOW *win, unsigned char *label, int y, int x, int selected)
+{
+ int i, temp;
+
+ wmove(win, y, x);
+ wattrset(win, selected ? button_active_attr : button_inactive_attr);
+ waddstr(win, selected ? "[" : " ");
+ temp = strspn(label, " ");
+ label += temp;
+ for (i = 0; i < temp; i++)
+ waddch(win, ' ');
+ wattrset(win, selected ? button_key_active_attr : button_key_inactive_attr);
+ waddch(win, label[0]);
+ wattrset(win, selected ? button_active_attr : button_inactive_attr);
+ waddstr(win, label+1);
+ waddstr(win, selected ? "]" : " ");
+ wmove(win, y, x+temp+1);
+}
+/* End of print_button() */
+
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void draw_box(WINDOW *win, int y, int x, int height, int width, chtype box, chtype border)
+{
+ int i, j;
+
+ wattrset(win, 0);
+ for (i = 0; i < height; i++) {
+ wmove(win, y + i, x);
+ for (j = 0; j < width; j++)
+ if (!i && !j)
+ waddch(win, border | ACS_ULCORNER);
+ else if (i == height-1 && !j)
+ waddch(win, border | ACS_LLCORNER);
+ else if (!i && j == width-1)
+ waddch(win, box | ACS_URCORNER);
+ else if (i == height-1 && j == width-1)
+ waddch(win, box | ACS_LRCORNER);
+ else if (!i)
+ waddch(win, border | ACS_HLINE);
+ else if (i == height-1)
+ waddch(win, box | ACS_HLINE);
+ else if (!j)
+ waddch(win, border | ACS_VLINE);
+ else if (j == width-1)
+ waddch(win, box | ACS_VLINE);
+ else
+ waddch(win, box | ' ');
+ }
+}
+/* End of draw_box() */
+
+
+#ifdef HAVE_NCURSES
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void draw_shadow(WINDOW *win, int y, int x, int height, int width)
+{
+ int i,sx,sy;
+ chtype attrs;
+
+ if (has_colors()) { /* Whether terminal supports color? */
+ getbegyx(win,sy,sx);
+ attrs = getattrs(win);
+ if (y+height < getmaxy(win)) {
+ /* small touch */
+ wattrset(win, A_INVIS);
+ wmove(win, y + height, x + 2);
+ for (i = 0; i < width; i++)
+ if (i+x+2 < getmaxx(win))
+ waddch(win, ' ');
+ /* end touch */
+ wattrset(win, shadow_attr);
+ wmove(win, y + height, x + 2);
+ for (i = 0; i < width; i++)
+ if (i+x+2 < getmaxx(win))
+ waddch(win, mvwinch(newscr, sy+y+height, sx+x+2+i) & A_CHARTEXT);
+ }
+ if (x+width < getmaxx(win)) {
+ for (i = y + 1; i < y + height + 1; i++) {
+ if (i < getmaxy(win)) {
+ /* small touch */
+ wattrset(win, A_INVIS);
+ wmove(win, i, x + width);
+ waddch(win, ' ');
+ if (x+width+1 < getmaxx(win))
+ waddch(win, ' ');
+ /* end touch */
+ wattrset(win, shadow_attr);
+ wmove(win, i, x + width);
+ waddch(win, mvwinch(newscr, sy+i, sx+x+width) & A_CHARTEXT);
+ if (x+width+1 < getmaxx(win))
+ waddch(win, mvwinch(newscr, sy+i, sx+x+width+1) & A_CHARTEXT);
+ }
+ }
+ }
+ wattrset(win, attrs);
+ wnoutrefresh(win);
+ }
+}
+/* End of draw_shadow() */
+#endif
+
+void dialog_clear_norefresh(void)
+{
+ attr_clear(stdscr, LINES, COLS, screen_attr);
+ touchwin(stdscr);
+ wnoutrefresh(stdscr);
+}
+
+void dialog_clear(void)
+{
+ dialog_clear_norefresh();
+ doupdate();
+}
+
+void dialog_update(void)
+{
+ refresh();
+}
+
+void end_dialog(void)
+{
+ endwin();
+}
+
+int strwidth(const char *p)
+{
+ int i = 0, len, incr;
+ const char *start, *s, *s1, *s2;
+
+ for (start = s = p; ; start = (s += incr)) {
+ s1 = strchr(s, '\n');
+ s2 = strstr(s, "\\n");
+ if (s2 == NULL)
+ s = s1;
+ else if (s1 == NULL)
+ s = s2;
+ else
+ s = MIN(s1, s2);
+ if (s == NULL)
+ break;
+ incr = 1 + (s == s2);
+ len = s - start;
+ if (len > i)
+ i = len;
+ }
+ len = strlen(start);
+ if (len > i)
+ i = len;
+ return i;
+}
+
+int strheight(const char *p)
+{
+ int i = 1, incr;
+ const char *s, *s1, *s2;
+
+ for (s = p; ; s += incr) {
+ s1 = strchr(s, '\n');
+ s2 = strstr(s, "\\n");
+ if (s2 == NULL)
+ s = s1;
+ else if (s1 == NULL)
+ s = s2;
+ else
+ s = MIN(s1, s2);
+ if (s == NULL)
+ break;
+ incr = 1 + (s == s2);
+ i++;
+ }
+ return i;
+}
+
+void print_arrows(WINDOW *dialog, int scroll, int menu_height, int item_no,
+ int box_x, int box_y, int tag_x, int cur_x, int cur_y)
+{
+ wmove(dialog, box_y, box_x + tag_x + 1);
+ wattrset(dialog, scroll ? uarrow_attr : menubox_attr);
+ waddch(dialog, scroll ? ACS_UARROW : ACS_HLINE);
+ wmove(dialog, box_y, box_x + tag_x + 2);
+ waddch(dialog, scroll ? '(' : ACS_HLINE);
+ wmove(dialog, box_y, box_x + tag_x + 3);
+ waddch(dialog, scroll ? '-' : ACS_HLINE);
+ wmove(dialog, box_y, box_x + tag_x + 4);
+ waddch(dialog, scroll ? ')' : ACS_HLINE);
+ wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 1);
+ wattrset(dialog, scroll+menu_height < item_no ? darrow_attr : menubox_border_attr);
+ waddch(dialog, scroll+menu_height < item_no ? ACS_DARROW : ACS_HLINE);
+ wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 2);
+ waddch(dialog, scroll+menu_height < item_no ? '(' : ACS_HLINE);
+ wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 3);
+ waddch(dialog, scroll+menu_height < item_no ? '+' : ACS_HLINE);
+ wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 4);
+ waddch(dialog, scroll+menu_height < item_no ? ')' : ACS_HLINE);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+}
+
diff --git a/gnu/lib/libodialog/lineedit.c b/gnu/lib/libodialog/lineedit.c
new file mode 100644
index 0000000..7bfe0e0
--- /dev/null
+++ b/gnu/lib/libodialog/lineedit.c
@@ -0,0 +1,213 @@
+/*
+ * Changes Copyright (C) 1995 by Andrey A. Chernov, Moscow
+ *
+ * Original Copyright:
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <dialog.h>
+#include "dialog.priv.h"
+
+static void redraw_field(WINDOW *dialog, int box_y, int box_x, int flen, int box_width, unsigned char instr[], int input_x, int scroll, chtype attr, chtype old_attr, int fexit, int attr_mask);
+
+/*
+ * Line editor
+ */
+int line_edit(WINDOW* dialog, int box_y, int box_x, int flen, int box_width, chtype attr, int first, unsigned char *result, int attr_mask)
+{
+ int i, key;
+ chtype old_attr;
+ static int input_x, scroll;
+ static unsigned char instr[MAX_LEN+1];
+ unsigned char erase_char = erasechar();
+ unsigned char kill_char = killchar();
+#ifdef notyet
+ unsignec char werase_char = cur_term->Ottyb.c_cc[VWERASE];
+#endif
+
+ old_attr = getattrs(dialog);
+ keypad(dialog, TRUE);
+
+ if (first) {
+ memset(instr, 0, sizeof(instr));
+ strcpy(instr, result);
+ i = strlen(instr);
+/* input_x = i % box_width;*/
+ input_x = (i > box_width) ? box_width - 1 : i;
+/* scroll = i - input_x;*/
+ scroll = (i > box_width) ? i - box_width + 1: 0;
+ }
+ redraw_field(dialog, box_y, box_x, flen, box_width, instr, input_x, scroll, attr, old_attr, FALSE, attr_mask);
+
+ for (;;) {
+ wattrset(dialog, attr);
+ wrefresh(dialog);
+ key = wgetch(dialog);
+ switch (key) {
+ case ctrl('q'):
+ goto ret;
+ break;
+ case KEY_F(1):
+ display_helpfile();
+ break;
+ case TAB:
+ case KEY_BTAB:
+ case KEY_UP:
+ case KEY_DOWN:
+ case ESC:
+ case '\r':
+ case '\n':
+ for (i = strlen(instr) - 1; i >= scroll + input_x && instr[i] == ' '; i--)
+ instr[i] = '\0';
+ if (key == '\r')
+ key = '\n';
+ goto ret;
+ case '\025':
+ case '\030':
+ kill_it:
+ input_x = scroll = 0;
+ /* fall through */
+ case '\013':
+ case KEY_EOL:
+ memset(instr + scroll + input_x, '\0', sizeof(instr) - scroll - input_x);
+ redraw_field(dialog, box_y, box_x, flen, box_width, instr, input_x, scroll, attr, old_attr, FALSE, attr_mask);
+ continue;
+ case '\001':
+ case KEY_HOME:
+ input_x = scroll = 0;
+ redraw_field(dialog, box_y, box_x, flen, box_width, instr, input_x, scroll, attr, old_attr, FALSE, attr_mask);
+ continue;
+ case '\005':
+ case KEY_END:
+ for (i = strlen(instr) - 1; i >= scroll + input_x && instr[i] == ' '; i--)
+ instr[i] = '\0';
+ i++;
+ input_x = i % box_width;
+ scroll = i - input_x;
+ redraw_field(dialog, box_y, box_x, flen, box_width, instr, input_x, scroll, attr, old_attr, FALSE, attr_mask);
+ continue;
+ case '\002':
+ case KEY_LEFT:
+ if (input_x || scroll) {
+ if (!input_x) {
+ int oldscroll = scroll;
+ scroll = scroll < box_width-1 ? 0 : scroll-(box_width-1);
+ input_x = oldscroll - 1 - scroll;
+ redraw_field(dialog, box_y, box_x, flen, box_width, instr, input_x, scroll, attr, old_attr, FALSE, attr_mask);
+ } else {
+ input_x--;
+ wmove(dialog, box_y, input_x + box_x);
+ }
+ } else
+ beep();
+ continue;
+ case '\006':
+ case KEY_RIGHT:
+ if ( scroll+input_x < MAX_LEN
+ && (flen < 0 || scroll+input_x < flen)
+ ) {
+ if (!instr[scroll+input_x])
+ instr[scroll+input_x] = ' ';
+ if (input_x == box_width-1) {
+ scroll++;
+ redraw_field(dialog, box_y, box_x, flen, box_width, instr, input_x, scroll, attr, old_attr, FALSE, attr_mask);
+ }
+ else {
+ wmove(dialog, box_y, input_x + box_x);
+ waddch(dialog, instr[scroll+input_x]);
+ input_x++;
+ }
+ } else
+ beep(); /* Alarm user about overflow */
+ continue;
+ case '\b':
+ case '\177':
+ case KEY_BACKSPACE:
+ erase_it:
+ if (input_x || scroll) {
+ i = strlen(instr);
+ memmove(instr+scroll+input_x-1, instr+scroll+input_x, i-(scroll+input_x)+1);
+ if (!input_x) {
+ int oldscroll = scroll;
+ scroll = scroll < box_width-1 ? 0 : scroll-(box_width-1);
+ input_x = oldscroll - 1 - scroll;
+ } else
+ input_x--;
+ redraw_field(dialog, box_y, box_x, flen, box_width, instr, input_x, scroll, attr, old_attr, FALSE, attr_mask);
+ } else
+ beep();
+ continue;
+ case '\004':
+ case KEY_DC:
+ for (i = strlen(instr) - 1; i >= scroll + input_x && instr[i] == ' '; i--)
+ instr[i] = '\0';
+ i++;
+ if (i == 0) {
+ beep();
+ continue;
+ }
+ memmove(instr+scroll+input_x, instr+scroll+input_x+1, i-(scroll+input_x));
+ redraw_field(dialog, box_y, box_x, flen, box_width, instr, input_x, scroll, attr, old_attr, FALSE, attr_mask);
+ continue;
+ default:
+ if (CCEQ(key, erase_char))
+ goto erase_it;
+ if (CCEQ(key, kill_char))
+ goto kill_it;
+ if (key < 0x100 && isprint(key)) {
+ for (i = strlen(instr) - 1; i >= scroll + input_x && instr[i] == ' '; i--)
+ instr[i] = '\0';
+ i++;
+ if (i < MAX_LEN && (flen < 0 || scroll+input_x < flen)) {
+ if (flen < 0 || i < flen)
+ memmove(instr+scroll+input_x+1, instr+scroll+input_x, i-(scroll+input_x));
+ instr[scroll+input_x] = key;
+ if (input_x == box_width-1 && (flen < 0 || i < flen))
+ scroll++;
+ else
+ input_x++;
+ redraw_field(dialog, box_y, box_x, flen, box_width, instr, input_x, scroll, attr, old_attr, FALSE, attr_mask);
+ } else
+ beep(); /* Alarm user about overflow */
+ continue;
+ }
+ }
+ }
+ret:
+ redraw_field(dialog, box_y, box_x, flen, box_width, instr, input_x, scroll, attr, old_attr, TRUE, attr_mask);
+ wrefresh(dialog);
+ strcpy(result, instr);
+ return key;
+}
+
+static void
+redraw_field(WINDOW *dialog, int box_y, int box_x, int flen, int box_width, unsigned char instr[], int input_x, int scroll, chtype attr, chtype old_attr, int fexit, int attr_mask)
+{
+ int i, fix_len;
+
+ wattrset(dialog, fexit ? old_attr : attr);
+ wmove(dialog, box_y, box_x);
+ fix_len = flen >= 0 ? MIN(flen-scroll,box_width) : box_width;
+ for (i = 0; i < fix_len; i++)
+ waddch(dialog, instr[scroll+i] ? ((attr_mask & DITEM_NO_ECHO) ? '*' : instr[scroll+i]) : ' ');
+ wattrset(dialog, old_attr);
+ for ( ; i < box_width; i++)
+ waddch(dialog, instr[scroll+i] ? ((attr_mask & DITEM_NO_ECHO) ? '*' : instr[scroll+i]) : ' ');
+ wmove(dialog, box_y, input_x + box_x);
+}
diff --git a/gnu/lib/libodialog/menubox.c b/gnu/lib/libodialog/menubox.c
new file mode 100644
index 0000000..a01acd5
--- /dev/null
+++ b/gnu/lib/libodialog/menubox.c
@@ -0,0 +1,469 @@
+/*
+ * menubox.c -- implements the menu box
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * Substantial rennovation: 12/18/95, Jordan K. Hubbard
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dialog.h>
+#include "dialog.priv.h"
+#include <err.h>
+#include <ncurses.h>
+
+static void print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int choice, int selected, dialogMenuItem *me, int menu_width, int tag_x, int item_x);
+
+#define DREF(di, item) ((di) ? &((di)[(item)]) : NULL)
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+int
+dialog_menu(unsigned char *title, unsigned char *prompt, int height, int width, int menu_height, int cnt, void *it, unsigned char *result, int *ch, int *sc)
+{
+ int i, j, x, y, cur_x, cur_y, box_x, box_y, key = 0, button, choice,
+ l, k, scroll, max_choice, item_no, redraw_menu = FALSE;
+ char okButton, cancelButton;
+ int rval = 0, ok_space, cancel_space;
+ WINDOW *dialog, *menu;
+ unsigned char **items = NULL;
+ dialogMenuItem *ditems;
+ int menu_width, tag_x, item_x;
+
+draw:
+ choice = ch ? *ch : 0;
+ scroll = sc ? *sc : 0;
+ button = 0;
+
+ /* If item_no is a positive integer, use old item specification format */
+ if (cnt >= 0) {
+ items = it;
+ ditems = NULL;
+ item_no = cnt;
+ }
+ /* It's the new specification format - fake the rest of the code out */
+ else {
+ item_no = abs(cnt);
+ ditems = it;
+ if (!items)
+ items = (unsigned char **)alloca((item_no * 2) * sizeof(unsigned char *));
+
+ /* Initializes status */
+ for (i = 0; i < item_no; i++) {
+ items[i*2] = ditems[i].prompt;
+ items[i*2 + 1] = ditems[i].title;
+ }
+ }
+ max_choice = MIN(menu_height, item_no);
+
+ tag_x = 0;
+ item_x = 0;
+ /* Find length of longest item in order to center menu */
+ for (i = 0; i < item_no; i++) {
+ l = strlen(items[i * 2]);
+ for (j = 0; j < item_no; j++) {
+ k = strlen(items[j * 2 + 1]);
+ tag_x = MAX(tag_x, l + k + 2);
+ }
+ item_x = MAX(item_x, l);
+ }
+ if (height < 0)
+ height = strheight(prompt) + menu_height + 4 + 2;
+ if (width < 0) {
+ i = strwidth(prompt);
+ j = ((title != NULL) ? strwidth(title) : 0);
+ width = MAX(i, j);
+ width = MAX(width, tag_x + 4) + 4;
+ }
+ width = MAX(width, 24);
+
+ if (width > COLS)
+ width = COLS;
+ if (height > LINES)
+ height = LINES;
+ /* center dialog box on screen */
+ x = DialogX ? DialogX : (COLS - width) / 2;
+ y = DialogY ? DialogY : (LINES - height) / 2;
+
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(stdscr, y, x, height, width);
+#endif
+ dialog = newwin(height, width, y, x);
+ if (dialog == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height, width, y, x);
+ return -1;
+ }
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+ wattrset(dialog, border_attr);
+ wmove(dialog, height - 3, 0);
+ waddch(dialog, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dialog_attr);
+ waddch(dialog, ACS_RTEE);
+ wmove(dialog, height - 2, 1);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ' ');
+
+ if (title != NULL) {
+ wattrset(dialog, title_attr);
+ wmove(dialog, 0, (width - strlen(title)) / 2 - 1);
+ waddch(dialog, ' ');
+ waddstr(dialog, title);
+ waddch(dialog, ' ');
+ }
+ wattrset(dialog, dialog_attr);
+ wmove(dialog, 1, 2);
+ print_autowrap(dialog, prompt, height - 1, width - 2, width, 1, 2, TRUE, FALSE);
+
+ menu_width = width - 6;
+ getyx(dialog, cur_y, cur_x);
+ box_y = cur_y + 1;
+ box_x = (width - menu_width) / 2 - 1;
+
+ /* create new window for the menu */
+ menu = subwin(dialog, menu_height, menu_width, y + box_y + 1, x + box_x + 1);
+ if (menu == NULL) {
+ delwin(dialog);
+ endwin();
+ fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", menu_height, menu_width,
+ y + box_y + 1, x + box_x + 1);
+ return -1;
+ }
+ keypad(menu, TRUE);
+
+ /* draw a box around the menu items */
+ draw_box(dialog, box_y, box_x, menu_height+2, menu_width+2, menubox_border_attr, menubox_attr);
+
+ tag_x = menu_width > tag_x + 1 ? (menu_width - tag_x) / 2 : 1;
+ item_x = menu_width > item_x + 4 ? tag_x + item_x + 2 : menu_width - 3;
+
+ /* Print the menu */
+ for (i = 0; i < max_choice; i++)
+ print_item(menu, items[(scroll + i) * 2], items[(scroll + i) * 2 + 1], i, i == choice, DREF(ditems, scroll + i), menu_width, tag_x, item_x);
+ wnoutrefresh(menu);
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y);
+
+ display_helpline(dialog, height - 1, width);
+
+ x = width / 2 - 11;
+ y = height - 2;
+
+ if (ditems && result) {
+ cancelButton = toupper(ditems[CANCEL_BUTTON].prompt[0]);
+ print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : FALSE);
+ okButton = toupper(ditems[OK_BUTTON].prompt[0]);
+ print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : TRUE);
+ }
+ else {
+ cancelButton = 'C';
+ print_button(dialog, "Cancel", y, x + 14, FALSE);
+ okButton = 'O';
+ print_button(dialog, " OK ", y, x, TRUE);
+ }
+
+ wrefresh(dialog);
+ while (key != ESC) {
+ key = wgetch(dialog);
+
+ /* Shortcut to OK? */
+ if (toupper(key) == okButton) {
+ if (ditems) {
+ if (result && ditems[OK_BUTTON].fire) {
+ int status;
+ WINDOW *save;
+
+ save = dupwin(newscr);
+ status = ditems[OK_BUTTON].fire(&ditems[OK_BUTTON]);
+ if (status & DITEM_RESTORE) {
+ touchwin(save);
+ wrefresh(save);
+ }
+ delwin(save);
+ }
+ }
+ else if (result)
+ strcpy(result, items[(scroll + choice) * 2]);
+ rval = 0;
+ key = ESC; /* Punt! */
+ break;
+ }
+
+ /* Shortcut to cancel? */
+ if (toupper(key) == cancelButton) {
+ if (ditems && result && ditems[CANCEL_BUTTON].fire) {
+ int status;
+ WINDOW *save;
+
+ save = dupwin(newscr);
+ status = ditems[CANCEL_BUTTON].fire(&ditems[CANCEL_BUTTON]);
+ if (status & DITEM_RESTORE) {
+ touchwin(save);
+ wrefresh(save);
+ }
+ delwin(save);
+ }
+ rval = 1;
+ key = ESC; /* Run away! */
+ break;
+ }
+
+ /* Check if key pressed matches first character of any item tag in menu */
+ for (i = 0; i < max_choice; i++)
+ if (key < 0x100 && key != ' ' && toupper(key) == toupper(items[(scroll + i) * 2][0]))
+ break;
+
+ if (i < max_choice || (key >= '1' && key <= MIN('9', '0'+max_choice)) || KEY_IS_UP(key) || KEY_IS_DOWN(key)) {
+ if (key >= '1' && key <= MIN('9', '0'+max_choice))
+ i = key - '1';
+ else if (KEY_IS_UP(key)) {
+ if (!choice) {
+ if (scroll) {
+ /* Scroll menu down */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ if (menu_height > 1) {
+ /* De-highlight current first item before scrolling down */
+ print_item(menu, items[scroll * 2], items[scroll * 2 + 1], 0, FALSE, DREF(ditems, scroll), menu_width, tag_x, item_x);
+ scrollok(menu, TRUE);
+ wscrl(menu, -1);
+ scrollok(menu, FALSE);
+ }
+ scroll--;
+ print_item(menu, items[scroll * 2], items[scroll * 2 + 1], 0, TRUE, DREF(ditems, scroll), menu_width, tag_x, item_x);
+ wnoutrefresh(menu);
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y);
+ wrefresh(dialog);
+ }
+ continue; /* wait for another key press */
+ }
+ else
+ i = choice - 1;
+ }
+ else if (KEY_IS_DOWN(key)) {
+ if (choice == max_choice - 1) {
+ if (scroll + choice < item_no - 1) {
+ /* Scroll menu up */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ if (menu_height > 1) {
+ /* De-highlight current last item before scrolling up */
+ print_item(menu, items[(scroll + max_choice - 1) * 2],
+ items[(scroll + max_choice - 1) * 2 + 1],
+ max_choice-1, FALSE, DREF(ditems, scroll + max_choice - 1), menu_width, tag_x, item_x);
+ scrollok(menu, TRUE);
+ scroll(menu);
+ scrollok(menu, FALSE);
+ }
+ scroll++;
+ print_item(menu, items[(scroll + max_choice - 1) * 2],
+ items[(scroll + max_choice - 1) * 2 + 1],
+ max_choice - 1, TRUE, DREF(ditems, scroll + max_choice - 1), menu_width, tag_x, item_x);
+ wnoutrefresh(menu);
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y);
+ wrefresh(dialog);
+ }
+ continue; /* wait for another key press */
+ }
+ else
+ i = choice + 1;
+ }
+
+ if (i != choice) {
+ /* De-highlight current item */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ print_item(menu, items[(scroll + choice) * 2], items[(scroll + choice) * 2 + 1], choice, FALSE, DREF(ditems, scroll + choice), menu_width, tag_x, item_x);
+
+ /* Highlight new item */
+ choice = i;
+ print_item(menu, items[(scroll + choice) * 2], items[(scroll + choice) * 2 + 1], choice, TRUE, DREF(ditems, scroll + choice), menu_width, tag_x, item_x);
+ wnoutrefresh(menu);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */
+ wrefresh(dialog);
+ }
+ continue; /* wait for another key press */
+ }
+
+ switch (key) {
+ case KEY_PPAGE:
+ if (scroll > height - 4) { /* can we go up? */
+ scroll -= (height - 4);
+ } else {
+ scroll = 0;
+ }
+ redraw_menu = TRUE;
+ break;
+
+ case KEY_NPAGE:
+ if (scroll + menu_height >= item_no-1 - menu_height) { /* can we go down a full page? */
+ scroll = item_no - menu_height;
+ if (scroll < 0)
+ scroll = 0;
+ } else {
+ scroll += menu_height;
+ }
+ redraw_menu = TRUE;
+ break;
+
+ case KEY_HOME:
+ scroll = 0;
+ choice = 0;
+ redraw_menu = TRUE;
+ break;
+
+ case KEY_END:
+ scroll = item_no - menu_height;
+ if (scroll < 0)
+ scroll = 0;
+ choice = max_choice - 1;
+ redraw_menu = TRUE;
+ break;
+
+ case KEY_BTAB:
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ button = !button;
+ if (ditems && result) {
+ print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5, ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
+ print_button(dialog, ditems[OK_BUTTON].prompt, y, x, ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
+ ok_space = 1;
+ cancel_space = strlen(ditems[OK_BUTTON].prompt) + 6;
+ }
+ else {
+ print_button(dialog, "Cancel", y, x + 14, button);
+ print_button(dialog, " OK ", y, x, !button);
+ ok_space = 3;
+ cancel_space = 15;
+ }
+ if (button)
+ wmove(dialog, y, x+cancel_space);
+ else
+ wmove(dialog, y, x+ok_space);
+ wrefresh(dialog);
+ break;
+
+ case ' ':
+ case '\r':
+ case '\n':
+ if (!button) {
+ /* A fire routine can do just about anything to the screen, so be prepared
+ to accept some hints as to what to do in the aftermath. */
+ if (ditems) {
+ if (ditems[scroll + choice].fire) {
+ int status;
+ WINDOW *save;
+
+ save = dupwin(newscr);
+ status = ditems[scroll + choice].fire(&ditems[scroll + choice]);
+ if (status & DITEM_RESTORE) {
+ touchwin(save);
+ wrefresh(save);
+ }
+ delwin(save);
+ if (status & DITEM_CONTINUE)
+ continue;
+ else if (status & DITEM_LEAVE_MENU) {
+ /* Allow a fire action to take us out of the menu */
+ key = ESC;
+ break;
+ }
+ else if (status & DITEM_RECREATE) {
+ delwin(menu);
+ delwin(dialog);
+ dialog_clear();
+ goto draw;
+ }
+ }
+ }
+ else if (result)
+ strcpy(result, items[(scroll+choice)*2]);
+ }
+ rval = button;
+ key = ESC;
+ break;
+
+ case ESC:
+ rval = -1;
+ break;
+
+ case KEY_F(1):
+ case '?':
+ display_helpfile();
+ break;
+ }
+
+ /* save info about menu item position */
+ if (ch)
+ *ch = choice;
+ if (sc)
+ *sc = scroll;
+
+ if (redraw_menu) {
+ for (i = 0; i < max_choice; i++) {
+ print_item(menu, items[(scroll + i) * 2], items[(scroll + i) * 2 + 1], i, i == choice, DREF(ditems, scroll + i), menu_width, tag_x, item_x);
+ }
+ wnoutrefresh(menu);
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, tag_x, cur_x, cur_y);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */
+ wrefresh(dialog);
+ redraw_menu = FALSE;
+ }
+ }
+ delwin(menu);
+ delwin(dialog);
+ return rval;
+}
+
+
+/*
+ * Print menu item
+ */
+static void
+print_item(WINDOW *win, unsigned char *tag, unsigned char *item, int choice, int selected, dialogMenuItem *me, int menu_width, int tag_x, int item_x)
+{
+ int i;
+
+ if (tag == NULL)
+ errx(1, "bad parameter to print_item()\n");
+
+ /* Clear 'residue' of last item */
+ wattrset(win, menubox_attr);
+ wmove(win, choice, 0);
+ for (i = 0; i < menu_width; i++)
+ waddch(win, ' ');
+ wmove(win, choice, tag_x);
+ wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
+ waddch(win, tag[0]);
+ wattrset(win, selected ? tag_selected_attr : tag_attr);
+ waddnstr(win, tag + 1, item_x - tag_x - 3);
+ wmove(win, choice, item_x);
+ wattrset(win, selected ? item_selected_attr : item_attr);
+ waddnstr(win, item, menu_width - item_x - 1);
+ /* If have a selection handler for this, call it */
+ if (me && me->selected) {
+ wrefresh(win);
+ me->selected(me, selected);
+ }
+}
+/* End of print_item() */
diff --git a/gnu/lib/libodialog/msgbox.c b/gnu/lib/libodialog/msgbox.c
new file mode 100644
index 0000000..41d78c8
--- /dev/null
+++ b/gnu/lib/libodialog/msgbox.c
@@ -0,0 +1,346 @@
+/*
+ * msgbox.c -- implements the message box and info box
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dialog.h>
+#include "dialog.priv.h"
+
+
+/* local prototypes */
+static int getnlines(unsigned char *buf);
+static void print_page(WINDOW *win, int height, int width, unsigned char *buf, int startline, int hscroll);
+static void print_perc(WINDOW *win, int y, int x, float p);
+
+
+/*
+ * Display a message box. Program will pause and display an "OK" button
+ * if the parameter 'pause' is non-zero.
+ */
+int dialog_msgbox(unsigned char *title, unsigned char *prompt, int height, int width, int pause)
+{
+ int i, j, x, y, key = 0;
+ WINDOW *dialog;
+
+ if (height < 0)
+ height = strheight(prompt)+2+2*(!!pause);
+ if (width < 0) {
+ i = strwidth(prompt);
+ j = ((title != NULL) ? strwidth(title) : 0);
+ width = MAX(i,j)+4;
+ }
+ if (pause)
+ width = MAX(width,10);
+
+ if (width > COLS)
+ width = COLS;
+ if (height > LINES)
+ height = LINES;
+ /* center dialog box on screen */
+ x = DialogX ? DialogX : (COLS - width)/2;
+ y = DialogY ? DialogY : (LINES - height)/2;
+
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(stdscr, y, x, height, width);
+#endif
+ dialog = newwin(height, width, y, x);
+ if (dialog == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width,y,x);
+ exit(1);
+ }
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+
+ if (title != NULL) {
+ wattrset(dialog, title_attr);
+ wmove(dialog, 0, (width - strlen(title))/2 - 1);
+ waddch(dialog, ' ');
+ waddstr(dialog, title);
+ waddch(dialog, ' ');
+ }
+ wattrset(dialog, dialog_attr);
+ wmove(dialog, 1, 2);
+ print_autowrap(dialog, prompt, height-1, width-2, width, 1, 2, TRUE, FALSE);
+
+ if (pause) {
+ wattrset(dialog, border_attr);
+ wmove(dialog, height-3, 0);
+ waddch(dialog, ACS_LTEE);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dialog_attr);
+ waddch(dialog, ACS_RTEE);
+ wmove(dialog, height-2, 1);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ' ');
+ display_helpline(dialog, height-1, width);
+ print_button(dialog, " OK ", height-2, width/2-6, TRUE);
+ wrefresh(dialog);
+ while (key != ESC && key != '\n' && key != ' ' && key != '\r')
+ key = wgetch(dialog);
+ if (key == '\r')
+ key = '\n';
+ }
+ else {
+ key = '\n';
+ wrefresh(dialog);
+ }
+
+ delwin(dialog);
+ return (key == ESC ? -1 : 0);
+}
+/* End of dialog_msgbox() */
+
+int
+dialog_mesgbox(unsigned char *title, unsigned char *prompt, int height, int width)
+/*
+ * Desc: basically the same as dialog_msgbox, but ... can use PGUP, PGDN and
+ * arrowkeys to move around the text and pause is always enabled
+ */
+{
+ int i, j, x, y, key=0;
+ int theight, startline, hscroll, max_lines;
+ WINDOW *dialog;
+
+ if (height < 0)
+ height = strheight(prompt)+2+2;
+ if (width < 0) {
+ i = strwidth(prompt);
+ j = ((title != NULL) ? strwidth(title) : 0);
+ width = MAX(i,j)+4;
+ }
+ width = MAX(width,10);
+
+ if (width > COLS)
+ width = COLS;
+ if (height > LINES)
+ height = LINES;
+ /* center dialog box on screen */
+ x = (COLS - width)/2;
+ y = (LINES - height)/2;
+
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(stdscr, y, x, height, width);
+#endif
+ dialog = newwin(height, width, y, x);
+ if (dialog == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width,y,x);
+ exit(1);
+ }
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+
+ if (title != NULL) {
+ wattrset(dialog, title_attr);
+ wmove(dialog, 0, (width - strlen(title))/2 - 1);
+ waddch(dialog, ' ');
+ waddstr(dialog, title);
+ waddch(dialog, ' ');
+ }
+
+ wattrset(dialog, border_attr);
+ wmove(dialog, height-3, 0);
+ waddch(dialog, ACS_LTEE);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dialog_attr);
+ waddch(dialog, ACS_RTEE);
+ wmove(dialog, height-2, 1);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ' ');
+ display_helpline(dialog, height-1, width);
+ print_button(dialog, " OK ", height-2, width/2-6, TRUE);
+ wattrset(dialog, dialog_attr);
+
+ theight = height - 4;
+ startline = 0;
+ hscroll = 0;
+ max_lines = getnlines(prompt);
+ print_page(dialog, theight, width, prompt, startline, hscroll);
+ print_perc(dialog, height-3, width-9, (float) (startline+theight)/max_lines);
+ wmove(dialog, height-2, width/2-3);
+ wrefresh(dialog);
+ while ((key != ESC) && (key != '\n') && (key != '\r') && (key != ' ')) {
+ key = wgetch(dialog);
+ switch(key) {
+ case KEY_HOME:
+ startline=0;
+ hscroll=0;
+ break;
+ case KEY_END:
+ startline = max_lines - theight;
+ if (startline < 0) startline = 0;
+ break;
+ case '\020': /* ^P */
+ case KEY_UP:
+ if (startline > 0) startline--;
+ break;
+ case '\016': /* ^N */
+ case KEY_DOWN:
+ if (startline < max_lines - theight) startline++;
+ break;
+ case KEY_RIGHT:
+ hscroll+=5;
+ break;
+ case KEY_LEFT:
+ if (hscroll > 0) hscroll-=5;
+ if (hscroll < 0) hscroll =0;
+ break;
+ case KEY_PPAGE:
+ if (startline - height > 0) {
+ startline -= theight;
+ } else {
+ startline = 0;
+ }
+ break;
+ case KEY_NPAGE:
+ if (startline + theight < max_lines - theight) {
+ startline += theight;
+ } else {
+ startline = max_lines - theight;
+ if (startline < 0) startline = 0;
+ }
+ break;
+ case KEY_F(1):
+ case '?':
+ display_helpfile();
+ break;
+ }
+ print_page(dialog, theight, width, prompt, startline, hscroll);
+ print_perc(dialog, height-3, width-9, (float) (startline+theight)/max_lines);
+ wmove(dialog, height-2, width/2-3);
+ wrefresh(dialog);
+ }
+
+ delwin(dialog);
+ return (key == ESC ? -1 : 0);
+
+} /* dialog_mesgbox() */
+
+static void
+print_perc(WINDOW *win, int y, int x, float p)
+/*
+ * Desc: print p as a percentage at the coordinates (y,x)
+ */
+{
+ char ps[10];
+
+ if (p>1.0) p=1.0;
+ sprintf(ps, "(%3d%%)", (int) (p*100));
+ wmove(win, y, x);
+ waddstr(win, ps);
+
+ return;
+} /* print_perc() */
+
+static int
+getnlines(unsigned char *buf)
+/*
+ * Desc: count the # of lines in <buf>
+ */
+{
+ int i = 0;
+
+ if (*buf)
+ i++;
+ while (*buf) {
+ if (*buf == '\n' || *buf == '\r')
+ i++;
+ buf++;
+ }
+ return(i);
+} /* getlines() */
+
+
+unsigned char *
+getline(unsigned char *buf, int n)
+/*
+ * Desc: return a pointer to the n'th line in <buf> or NULL if its
+ * not there
+ */
+{
+ int i;
+
+ if (n<0) {
+ return(NULL);
+ }
+
+ i=0;
+ while (*buf && i<n) {
+ if (*buf == '\n' || *buf == '\r') {
+ i++;
+ }
+ buf++;
+ }
+ if (i<n) {
+ return(NULL);
+ } else {
+ return(buf);
+ }
+} /* getline() */
+
+static void
+print_page(WINDOW *win, int height, int width, unsigned char *buf, int startline, int hscroll)
+/*
+ * Desc: Print a page of text in the current window, starting at line <startline>
+ * with a <horizontal> scroll of hscroll from buffer <buf>
+ */
+{
+ int i, j;
+ unsigned char *b;
+
+ b = getline(buf, startline);
+ for (i=0; i<height; i++) {
+ /* clear line */
+ wmove(win, 1+i, 1);
+ for (j=0; j<width-2; j++) waddnstr(win, " ", 1);
+ wmove(win, 1+i, 1);
+ j = 0;
+ /* scroll to the right */
+ while (*b && (*b != '\n') && (*b != '\r') && (j<hscroll)) {
+ b++;
+ j++;
+ }
+ /* print new line */
+ j = 0;
+ while (*b && (*b != '\n') && (*b != '\r') && (j<width-2)) {
+ waddnstr(win, b, 1);
+ if (*b != '\t') { /* check for tabs */
+ j++;
+ } else {
+ j = ((int) (j+1)/8 + 1) * 8 - 1;
+ }
+ b++;
+ }
+ while (*b && (*b != '\n') && (*b != '\r')) b++;
+ if (*b) b++; /* skip over '\n', if it exists */
+ }
+} /* print_page() */
+
+
+
+
diff --git a/gnu/lib/libodialog/notify.c b/gnu/lib/libodialog/notify.c
new file mode 100644
index 0000000..7fc22eb
--- /dev/null
+++ b/gnu/lib/libodialog/notify.c
@@ -0,0 +1,53 @@
+/*
+ * File: notify.c
+ * Author: Marc van Kempen
+ * Desc: display a notify box with a message
+ *
+ * Copyright (c) 1995, Marc van Kempen
+ *
+ * All rights reserved.
+ *
+ * This software may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dialog.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+dialog_notify(char *msg)
+/*
+ * Desc: display an error message
+ */
+{
+ char *tmphlp;
+ WINDOW *w;
+
+ w = dupwin(newscr);
+ if (w == NULL) {
+ endwin();
+ fprintf(stderr, "\ndupwin(newscr) failed, malloc memory corrupted\n");
+ exit(1);
+ }
+ tmphlp = get_helpline();
+ use_helpline("Press enter or space");
+ dialog_mesgbox("Message", msg, -1, -1);
+ restore_helpline(tmphlp);
+ touchwin(w);
+ wrefresh(w);
+ delwin(w);
+
+ return;
+
+} /* dialog_notify() */
+
diff --git a/gnu/lib/libodialog/prgbox.c b/gnu/lib/libodialog/prgbox.c
new file mode 100644
index 0000000..bcafacf
--- /dev/null
+++ b/gnu/lib/libodialog/prgbox.c
@@ -0,0 +1,152 @@
+/*
+ * prgbox.c -- implements the message box and info box
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <dialog.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include "dialog.priv.h"
+
+/*
+ * Display a message box. Program will pause and display an "OK" button
+ * if the parameter 'pause' is non-zero.
+ */
+int dialog_prgbox(unsigned char *title, const unsigned char *line, int height, int width, int pause, int use_shell)
+{
+ int i, x, y, key = 0;
+ WINDOW *dialog;
+ FILE *f;
+ const unsigned char *name;
+ unsigned char *s, buf[MAX_LEN];
+ int status;
+
+ if (height < 0 || width < 0) {
+ endwin();
+ fprintf(stderr, "\nAutosizing is impossible in dialog_prgbox().\n");
+ exit(-1);
+ }
+ width = MAX(width,10);
+
+ if (width > COLS)
+ width = COLS;
+ if (height > LINES)
+ height = LINES;
+ /* center dialog box on screen */
+ x = DialogX ? DialogX : (COLS - width)/2;
+ y = DialogY ? DialogY : (LINES - height)/2;
+
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(stdscr, y, x, height, width);
+#endif
+ dialog = newwin(height, width, y, x);
+ if (dialog == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width,y,x);
+ exit(1);
+ }
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+
+ if (title != NULL) {
+ wattrset(dialog, title_attr);
+ wmove(dialog, 0, (width - strlen(title))/2 - 1);
+ waddch(dialog, ' ');
+ waddstr(dialog, title);
+ waddch(dialog, ' ');
+ }
+ wattrset(dialog, dialog_attr);
+ wmove(dialog, 1, 2);
+
+ if (!use_shell) {
+ char cmdline[MAX_LEN];
+ char *av[51], **ap = av, *val, *p;
+
+ strcpy(cmdline, line);
+ p = cmdline;
+ while ((val = strsep(&p," \t")) != NULL) {
+ if (*val != '\0')
+ *ap++ = val;
+ }
+ *ap = NULL;
+ f = raw_popen(name = av[0], av, "r");
+ } else
+ f = raw_popen(name = line, NULL, "r");
+
+ status = -1;
+ if (f == NULL) {
+ err:
+ sprintf(buf, "%s: %s\n", name, strerror(errno));
+ prr:
+ print_autowrap(dialog, buf, height-(pause?3:1), width-2, width, 1, 2, FALSE, TRUE);
+ wrefresh(dialog);
+ } else {
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+ i = strlen(buf);
+ if (buf[i-1] == '\n')
+ buf[i-1] = '\0';
+ s = buf;
+ while ((s = strchr(s, '\t')) != NULL)
+ *s++ = ' ';
+ print_autowrap(dialog, buf, height-(pause?3:1), width-2, width, 1, 2, FALSE, TRUE);
+ print_autowrap(dialog, "\n", height-(pause?3:1), width-2, width, 1, 2, FALSE, FALSE);
+ wrefresh(dialog);
+ }
+ if ((status = raw_pclose(f)) == -1)
+ goto err;
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 127) {
+ sprintf(buf, "%s: program not found\n", name);
+ goto prr;
+ }
+ }
+
+ if (pause) {
+ wattrset(dialog, border_attr);
+ wmove(dialog, height-3, 0);
+ waddch(dialog, ACS_LTEE);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dialog_attr);
+ waddch(dialog, ACS_RTEE);
+ wmove(dialog, height-2, 1);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ' ');
+ display_helpline(dialog, height-1, width);
+ print_button(dialog, " OK ", height-2, width/2-6, TRUE);
+ wrefresh(dialog);
+ while (key != ESC && key != '\n' && key != ' ' && key != '\r')
+ key = wgetch(dialog);
+ if (key == '\r')
+ key = '\n';
+ }
+ else {
+ key = '\n';
+ wrefresh(dialog);
+ }
+
+ delwin(dialog);
+ return (status);
+}
+/* End of dialog_msgbox() */
diff --git a/gnu/lib/libodialog/radiolist.c b/gnu/lib/libodialog/radiolist.c
new file mode 100644
index 0000000..4b865a6
--- /dev/null
+++ b/gnu/lib/libodialog/radiolist.c
@@ -0,0 +1,628 @@
+/*
+ * radiolist.c -- implements the radiolist box
+ *
+ * AUTHOR: Stuart Herbert - S.Herbert@sheffield.ac.uk
+ * (from checklist.c by Savio Lam (lam836@cs.cuhk.hk))
+ *
+ * Substantial rennovation: 12/18/95, Jordan K. Hubbard
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dialog.h>
+#include "dialog.priv.h"
+
+
+static void print_item(WINDOW *win, char *tag, char *item, int status, int choice, int selected, dialogMenuItem *me);
+
+#define DREF(di, item) ((di) ? &((di)[(item)]) : NULL)
+
+static int list_width, check_x, item_x;
+
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ */
+int
+dialog_radiolist(unsigned char *title, unsigned char *prompt, int height, int width, int list_height,
+ int cnt, void *it, unsigned char *result)
+{
+ int i, j, x, y, cur_x, cur_y, old_x, old_y, box_x, box_y, key = 0, button,
+ choice, l, k, scroll, max_choice, *status, item_no = 0, was_on = 0;
+ int redraw_menu = FALSE, cursor_reset = FALSE;
+ int rval = 0, onlist = 1, ok_space, cancel_space;
+ char okButton, cancelButton;
+ WINDOW *dialog, *list;
+ unsigned char **items = NULL;
+ dialogMenuItem *ditems;
+
+ /* Allocate space for storing item on/off status */
+ if ((status = alloca(sizeof(int) * abs(cnt))) == NULL) {
+ endwin();
+ fprintf(stderr, "\nCan't allocate memory in dialog_radiolist().\n");
+ exit(-1);
+ }
+
+draw:
+ button = choice = scroll = 0;
+ /* Previous calling syntax, e.g. just a list of strings? */
+ if (cnt >= 0) {
+ items = it;
+ ditems = NULL;
+ item_no = cnt;
+ /* Initializes status */
+ for (i = 0; i < item_no; i++) {
+ status[i] = !strcasecmp(items[i*3 + 2], "on");
+ if (status[i]) {
+ if (was_on)
+ status[i] = FALSE;
+ else
+ was_on = 1;
+ }
+ }
+ }
+ /* It's the new specification format - fake the rest of the code out */
+ else {
+ item_no = abs(cnt);
+ ditems = it;
+ if (!items)
+ items = (unsigned char **)alloca((item_no * 3) * sizeof(unsigned char *));
+ /* Initializes status */
+ for (i = 0; i < item_no; i++) {
+ status[i] = ditems[i].checked ? ditems[i].checked(&ditems[i]) : FALSE;
+ if (status[i]) {
+ if (was_on)
+ status[i] = FALSE;
+ else
+ was_on = 1;
+ }
+ items[i*3] = ditems[i].prompt;
+ items[i*3 + 1] = ditems[i].title;
+ items[i*3 + 2] = status[i] ? "on" : "off";
+ }
+ }
+ max_choice = MIN(list_height, item_no);
+
+ check_x = 0;
+ item_x = 0;
+ /* Find length of longest item in order to center radiolist */
+ for (i = 0; i < item_no; i++) {
+ l = strlen(items[i * 3]);
+ for (j = 0; j < item_no; j++) {
+ k = strlen(items[j * 3 + 1]);
+ check_x = MAX(check_x, l + k + 6);
+ }
+ item_x = MAX(item_x, l);
+ }
+ if (height < 0)
+ height = strheight(prompt) + list_height + 4 + 2;
+ if (width < 0) {
+ i = strwidth(prompt);
+ j = ((title != NULL) ? strwidth(title) : 0);
+ width = MAX(i, j);
+ width = MAX(width, check_x + 4) + 4;
+ }
+ width = MAX(width, 24);
+
+ if (width > COLS)
+ width = COLS;
+ if (height > LINES)
+ height = LINES;
+ /* center dialog box on screen */
+ x = DialogX ? DialogX : (COLS - width) / 2;
+ y = DialogY ? DialogY : (LINES - height) / 2;
+
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(stdscr, y, x, height, width);
+#endif
+ dialog = newwin(height, width, y, x);
+ if (dialog == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height, width, y, x);
+ return -1;
+ }
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+ wattrset(dialog, border_attr);
+ wmove(dialog, height - 3, 0);
+ waddch(dialog, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dialog_attr);
+ waddch(dialog, ACS_RTEE);
+ wmove(dialog, height - 2, 1);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ' ');
+
+ if (title != NULL) {
+ wattrset(dialog, title_attr);
+ wmove(dialog, 0, (width - strlen(title)) / 2 - 1);
+ waddch(dialog, ' ');
+ waddstr(dialog, title);
+ waddch(dialog, ' ');
+ }
+ wattrset(dialog, dialog_attr);
+ wmove(dialog, 1, 2);
+ print_autowrap(dialog, prompt, height - 1, width - 2, width, 1, 2, TRUE, FALSE);
+
+ list_width = width - 6;
+ getyx(dialog, cur_y, cur_x);
+ box_y = cur_y + 1;
+ box_x = (width - list_width) / 2 - 1;
+
+ /* create new window for the list */
+ list = subwin(dialog, list_height, list_width, y + box_y + 1, x + box_x + 1);
+ if (list == NULL) {
+ delwin(dialog);
+ endwin();
+ fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", list_height, list_width,
+ y + box_y + 1,x + box_x + 1);
+ return -1;
+ }
+ keypad(list, TRUE);
+
+ /* draw a box around the list items */
+ draw_box(dialog, box_y, box_x, list_height+2, list_width+2, menubox_border_attr, menubox_attr);
+
+ check_x = (list_width - check_x) / 2;
+ item_x = check_x + item_x + 6;
+
+ /* Print the list */
+ for (i = 0; i < max_choice; i++)
+ print_item(list, items[i * 3], items[i * 3 + 1], status[i], i, i == choice, DREF(ditems, i));
+ wnoutrefresh(list);
+ print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
+
+ display_helpline(dialog, height-1, width);
+
+ x = width/ 2 - 11;
+ y = height - 2;
+ if (ditems && result) {
+ cancelButton = toupper(ditems[CANCEL_BUTTON].prompt[0]);
+ print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5,
+ ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : FALSE);
+ okButton = toupper(ditems[OK_BUTTON].prompt[0]);
+ print_button(dialog, ditems[OK_BUTTON].prompt, y, x,
+ ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : TRUE);
+ }
+ else {
+ cancelButton = 'C';
+ print_button(dialog, "Cancel", y, x + 14, FALSE);
+ okButton = 'O';
+ print_button(dialog, " OK ", y, x, TRUE);
+ }
+ wnoutrefresh(dialog);
+ wmove(list, choice, check_x+1);
+ wrefresh(list);
+
+ while (key != ESC) {
+ key = wgetch(dialog);
+
+ /* See if its the short-cut to "OK" */
+ if (toupper(key) == okButton) {
+ if (ditems) {
+ if (result && ditems[OK_BUTTON].fire) {
+ int st;
+ WINDOW *save;
+
+ save = dupwin(newscr);
+ st = ditems[OK_BUTTON].fire(&ditems[OK_BUTTON]);
+ if (st & DITEM_RESTORE) {
+ touchwin(save);
+ wrefresh(save);
+ }
+ delwin(save);
+ }
+ }
+ else if (result) {
+ *result = '\0';
+ for (i = 0; i < item_no; i++) {
+ if (status[i]) {
+ strcat(result, items[i*3]);
+ break;
+ }
+ }
+ }
+ rval = 0;
+ key = ESC;
+ break;
+ }
+
+ /* Shortcut to cancel */
+ if (toupper(key) == cancelButton) {
+ if (ditems && result && ditems[CANCEL_BUTTON].fire) {
+ int st;
+ WINDOW *save;
+
+ save = dupwin(newscr);
+ st = ditems[CANCEL_BUTTON].fire(&ditems[CANCEL_BUTTON]);
+ if (st & DITEM_RESTORE) {
+ touchwin(save);
+ wrefresh(save);
+ }
+ delwin(save);
+ }
+ rval = 1;
+ key = ESC;
+ break;
+ }
+
+ /* Check if key pressed matches first character of any item tag in list */
+ for (i = 0; i < max_choice; i++)
+ if (key != ' ' && toupper(key) == toupper(items[(scroll + i) * 3][0]))
+ break;
+
+ if (i < max_choice || (key >= '1' && key <= MIN('9', '0' + max_choice)) ||
+ KEY_IS_UP(key) || KEY_IS_DOWN(key) || ((key == ' ' || key == '\r' || key == '\n') && onlist == 1)) {
+
+ /* if moving from buttons to the list, reset and redraw buttons */
+ if (!onlist) {
+ onlist = 1;
+ button = 0;
+
+ if (ditems && result ) {
+ print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5,
+ ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
+ print_button(dialog, ditems[OK_BUTTON].prompt, y, x,
+ ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
+ }
+ else {
+ print_button(dialog, "Cancel", y, x + 14, button);
+ print_button(dialog, " OK ", y, x, !button);
+ }
+ }
+ wmove(list, choice, check_x+1);
+ wnoutrefresh(dialog);
+ wrefresh(list);
+
+ if (key >= '1' && key <= MIN('9', '0' + max_choice))
+ i = key - '1';
+ else if (KEY_IS_UP(key)) {
+ if (!choice) {
+ if (scroll) {
+ /* Scroll list down */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ if (list_height > 1) {
+ /* De-highlight current first item before scrolling down */
+ print_item(list, items[scroll*3], items[scroll*3 + 1], status[scroll], 0,
+ FALSE, DREF(ditems, scroll));
+ scrollok(list, TRUE);
+ wscrl(list, -1);
+ scrollok(list, FALSE);
+ }
+ scroll--;
+ print_item(list, items[scroll*3], items[scroll*3 + 1], status[scroll], 0,
+ TRUE, DREF(ditems, scroll));
+ print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
+ wmove(list, choice, check_x+1);
+ wnoutrefresh(dialog);
+ wrefresh(list);
+ }
+ continue; /* wait for another key press */
+ }
+ else
+ i = choice - 1;
+ }
+ else if (KEY_IS_DOWN(key)) {
+ if (choice == max_choice - 1) {
+ if (scroll + choice < item_no - 1) {
+ /* Scroll list up */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ if (list_height > 1) {
+ /* De-highlight current last item before scrolling up */
+ print_item(list, items[(scroll + max_choice - 1) * 3],
+ items[(scroll + max_choice - 1) * 3 + 1],
+ status[scroll + max_choice - 1], max_choice - 1,
+ FALSE, DREF(ditems, scroll + max_choice - 1));
+ scrollok(list, TRUE);
+ scroll(list);
+ scrollok(list, FALSE);
+ }
+ scroll++;
+ print_item(list, items[(scroll + max_choice - 1) * 3],
+ items[(scroll + max_choice - 1) * 3 + 1],
+ status[scroll + max_choice - 1], max_choice - 1,
+ TRUE, DREF(ditems, scroll + max_choice - 1));
+ print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
+ wmove(list, choice, check_x+1);
+ wnoutrefresh(dialog);
+ wrefresh(list);
+ }
+ continue; /* wait for another key press */
+ }
+ else
+ i = choice + 1;
+ }
+ else if ((key == ' ' || key == '\r' || key == '\n') && onlist) { /* Toggle item status */
+ getyx(list, old_y, old_x); /* Save cursor position */
+ if (status[scroll + choice])
+ continue;
+ else if (ditems) {
+ if (ditems[scroll + choice].fire) {
+ int st;
+ WINDOW *save;
+
+ save = dupwin(newscr);
+ st = ditems[scroll + choice].fire(&ditems[scroll + choice]);
+ if (st & DITEM_RESTORE) {
+ touchwin(save);
+ wrefresh(save);
+ }
+ delwin(save);
+ if (st & DITEM_REDRAW) {
+ wclear(list);
+ for (i = 0; i < item_no; i++)
+ status[i] = ditems[i].checked ? ditems[i].checked(&ditems[i]) : FALSE;
+
+ for (i = 0; i < max_choice; i++) {
+ print_item(list, items[(scroll + i) * 3], items[(scroll + i) * 3 + 1],
+ status[scroll + i], i, i == choice,
+ DREF(ditems, scroll + i));
+ }
+/* wmove(list, old_y, old_x);*/ /* Restore cursor to previous position */
+/* wrefresh(list); */
+ }
+ if (st & DITEM_LEAVE_MENU) {
+ /* Allow a fire action to take us out of the menu */
+ key = ESC;
+ break;
+ }
+ else if (st & DITEM_RECREATE) {
+ delwin(list);
+ delwin(dialog);
+ dialog_clear();
+ goto draw;
+ }
+ }
+ for (i = 0; i < item_no; i++)
+ status[i] = ditems[i].checked ? ditems[i].checked(&ditems[i]) : FALSE;
+ }
+ else {
+ for (i = 0; i < item_no; i++)
+ status[i] = 0;
+ status[scroll + choice] = TRUE;
+ }
+ for (i = 0; i < max_choice; i++)
+ print_item(list, items[(scroll + i) * 3], items[(scroll + i) * 3 + 1],
+ status[scroll + i], i, i == choice, DREF(ditems, scroll + i));
+ wmove(list, choice, check_x+1); /* Restore cursor position */
+ wrefresh(list);
+ continue; /* wait for another key press */
+ }
+
+ if (i != choice) {
+ /* De-highlight current item */
+ print_item(list, items[(scroll + choice) * 3], items[(scroll + choice) * 3 +1],
+ status[scroll + choice], choice, FALSE, DREF(ditems, scroll + choice));
+ /* Highlight new item */
+ choice = i;
+ print_item(list, items[(scroll + choice) * 3], items[(scroll + choice) * 3 + 1],
+ status[scroll + choice], choice, TRUE, DREF(ditems, scroll + choice));
+ wmove(list, choice, check_x+1); /* Restore cursor position */
+ wrefresh(list);
+ }
+ continue; /* wait for another key press */
+ }
+
+ switch (key) {
+ case KEY_PPAGE:
+ if (scroll > height-4) /* can we go up? */
+ scroll -= (height-4);
+ else
+ scroll = 0;
+ redraw_menu = TRUE;
+ if (!onlist) {
+ onlist = 1;
+ button = 0;
+ }
+ break;
+
+ case KEY_NPAGE:
+ if (scroll + list_height >= item_no-1 - list_height) { /* can we go down a full page? */
+ scroll = item_no - list_height;
+ if (scroll < 0)
+ scroll = 0;
+ }
+ else
+ scroll += list_height;
+ redraw_menu = TRUE;
+ if (!onlist) {
+ onlist = 1;
+ button = 0;
+ }
+ break;
+
+ case KEY_HOME:
+ scroll = 0;
+ choice = 0;
+ redraw_menu = TRUE;
+ cursor_reset = TRUE;
+ onlist = 1;
+ break;
+
+ case KEY_END:
+ scroll = item_no - list_height;
+ if (scroll < 0)
+ scroll = 0;
+ choice = max_choice - 1;
+ redraw_menu = TRUE;
+ cursor_reset = TRUE;
+ onlist = 1;
+ break;
+
+ case TAB:
+ case KEY_BTAB:
+ /* move to next component */
+ if (onlist) { /* on list, next is ok button */
+ onlist = 0;
+ if (ditems && result)
+ ok_space = 1;
+ else
+ ok_space = 3;
+ wmove(dialog, y, x + ok_space);
+ wrefresh(dialog);
+ break;
+ }
+ else if (button) { /* on cancel button, next is list */
+ button = 0;
+ onlist = 1;
+ redraw_menu = TRUE;
+ break;
+ }
+ /* on ok button, next is cancel button, same as left/right case */
+
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ onlist = 0;
+ button = !button;
+ if (ditems && result) {
+ print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5,
+ ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
+ print_button(dialog, ditems[OK_BUTTON].prompt, y, x,
+ ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
+ ok_space = 1;
+ cancel_space = strlen(ditems[OK_BUTTON].prompt) + 6;
+ }
+ else {
+ print_button(dialog, "Cancel", y, x + 14, button);
+ print_button(dialog, " OK ", y, x, !button);
+ ok_space = 3;
+ cancel_space = 15;
+ }
+ if (button)
+ wmove(dialog, y, x + cancel_space);
+ else
+ wmove(dialog, y, x + ok_space);
+ wrefresh(dialog);
+ break;
+
+ case ' ':
+ case '\r':
+ case '\n':
+ if (!onlist) {
+ if (ditems) {
+ if (result && ditems[button ? CANCEL_BUTTON : OK_BUTTON].fire) {
+ int st;
+ WINDOW *save;
+
+ save = dupwin(newscr);
+ st = ditems[button ? CANCEL_BUTTON : OK_BUTTON].fire(&ditems[button ? CANCEL_BUTTON : OK_BUTTON]);
+ if (st & DITEM_RESTORE) {
+ touchwin(save);
+ wrefresh(save);
+ }
+ delwin(save);
+ }
+ }
+ else if (result) {
+ *result = '\0';
+ for (i = 0; i < item_no; i++) {
+ if (status[i]) {
+ strcpy(result, items[i*3]);
+ break;
+ }
+ }
+ }
+ rval = button;
+ key = ESC;
+ break;
+ }
+
+ case ESC:
+ rval = -1;
+ break;
+
+ case KEY_F(1):
+ case '?':
+ display_helpfile();
+ break;
+ }
+
+ if (redraw_menu) {
+ getyx(list, old_y, old_x);
+ wclear(list);
+ for (i = 0; i < max_choice; i++)
+ print_item(list, items[(scroll + i) * 3], items[(scroll + i) * 3 + 1], status[scroll + i],
+ i, i == choice, DREF(ditems, scroll + i));
+ print_arrows(dialog, scroll, list_height, item_no, box_x, box_y, check_x + 4, cur_x, cur_y);
+
+ /* redraw buttons to fix highlighting */
+ if (ditems && result) {
+ print_button(dialog, ditems[CANCEL_BUTTON].prompt, y, x + strlen(ditems[OK_BUTTON].prompt) + 5,
+ ditems[CANCEL_BUTTON].checked ? ditems[CANCEL_BUTTON].checked(&ditems[CANCEL_BUTTON]) : button);
+ print_button(dialog, ditems[OK_BUTTON].prompt, y, x,
+ ditems[OK_BUTTON].checked ? ditems[OK_BUTTON].checked(&ditems[OK_BUTTON]) : !button);
+ }
+ else {
+ print_button(dialog, "Cancel", y, x + 14, button);
+ print_button(dialog, " OK ", y, x, !button);
+ }
+ wnoutrefresh(dialog);
+ if (cursor_reset) {
+ wmove(list, choice, check_x+1);
+ cursor_reset = FALSE;
+ }
+ else {
+ wmove(list, old_y, old_x);
+ }
+ wrefresh(list);
+ redraw_menu = FALSE;
+ }
+ }
+
+ delwin(list);
+ delwin(dialog);
+ return rval; /* ESC pressed */
+}
+
+/*
+ * Print list item
+ */
+static void
+print_item(WINDOW *win, char *tag, char *item, int status, int choice, int selected, dialogMenuItem *me)
+{
+ int i;
+
+ /* Clear 'residue' of last item */
+ wattrset(win, menubox_attr);
+ wmove(win, choice, 0);
+ for (i = 0; i < list_width; i++)
+ waddch(win, ' ');
+ wmove(win, choice, check_x);
+ wattrset(win, selected ? check_selected_attr : check_attr);
+ wprintw(win, "%c%c%c", me && me->lbra ? me->lbra : '(',
+ status ? me && me->mark ? me->mark : '*' : ' ',
+ me && me->rbra ? me->rbra : ')');
+ wattrset(win, menubox_attr);
+ waddch(win, ' ');
+ wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
+ waddch(win, tag[0]);
+ wattrset(win, selected ? tag_selected_attr : tag_attr);
+ waddstr(win, tag + 1);
+ wmove(win, choice, item_x);
+ wattrset(win, selected ? item_selected_attr : item_attr);
+ waddstr(win, item);
+ /* If have a selection handler for this, call it */
+ if (me && me->selected) {
+ wrefresh(win);
+ me->selected(me, selected);
+ }
+}
+/* End of print_item() */
diff --git a/gnu/lib/libodialog/raw_popen.c b/gnu/lib/libodialog/raw_popen.c
new file mode 100644
index 0000000..163c09a
--- /dev/null
+++ b/gnu/lib/libodialog/raw_popen.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software written by Ken Arnold and
+ * published in UNIX Review, Vol. 6, No. 8.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/wait.h>
+
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+
+static struct pid {
+ struct pid *next;
+ FILE *fp;
+ pid_t pid;
+} *pidlist;
+
+FILE *
+raw_popen(const char *program, char * const *argv, const char *type)
+{
+ struct pid *cur;
+ FILE *iop;
+ int pdes[2], pid;
+
+ if ((*type != 'r' && *type != 'w') || type[1])
+ return (NULL);
+
+ if ((cur = malloc(sizeof(struct pid))) == NULL)
+ return (NULL);
+
+ if (pipe(pdes) < 0) {
+ (void)free(cur);
+ return (NULL);
+ }
+
+ switch (pid = vfork()) {
+ case -1: /* Error. */
+ (void)close(pdes[0]);
+ (void)close(pdes[1]);
+ (void)free(cur);
+ return (NULL);
+ /* NOTREACHED */
+ case 0: /* Child. */
+ if (*type == 'r') {
+ if (pdes[1] != STDOUT_FILENO) {
+ (void)dup2(pdes[1], STDOUT_FILENO);
+ (void)close(pdes[1]);
+ }
+ (void) close(pdes[0]);
+ } else {
+ if (pdes[0] != STDIN_FILENO) {
+ (void)dup2(pdes[0], STDIN_FILENO);
+ (void)close(pdes[0]);
+ }
+ (void)close(pdes[1]);
+ }
+ if (argv == NULL)
+ execl(_PATH_BSHELL, "sh", "-c", program, (char *)NULL);
+ else
+ execvp(program, argv);
+ _exit(127);
+ /* NOTREACHED */
+ }
+
+ /* Parent; assume fdopen can't fail. */
+ if (*type == 'r') {
+ iop = fdopen(pdes[0], type);
+ (void)close(pdes[1]);
+ } else {
+ iop = fdopen(pdes[1], type);
+ (void)close(pdes[0]);
+ }
+
+ /* Link into list of file descriptors. */
+ cur->fp = iop;
+ cur->pid = pid;
+ cur->next = pidlist;
+ pidlist = cur;
+
+ return (iop);
+}
+
+/*
+ * pclose --
+ * Pclose returns -1 if stream is not associated with a `popened' command,
+ * if already `pclosed', or waitpid returns an error.
+ */
+int
+raw_pclose(FILE *iop)
+{
+ register struct pid *cur, *last;
+ int omask, pstat;
+ pid_t pid;
+
+ (void)fclose(iop);
+
+ /* Find the appropriate file pointer. */
+ for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
+ if (cur->fp == iop)
+ break;
+ if (cur == NULL)
+ return (-1);
+
+ /* Get the status of the process. */
+ omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
+ do {
+ pid = waitpid(cur->pid, (int *) &pstat, 0);
+ } while (pid == -1 && errno == EINTR);
+ (void)sigsetmask(omask);
+
+ /* Remove the entry from the linked list. */
+ if (last == NULL)
+ pidlist = cur->next;
+ else
+ last->next = cur->next;
+ free(cur);
+
+ return (pid == -1 ? -1 : pstat);
+}
diff --git a/gnu/lib/libodialog/rc.c b/gnu/lib/libodialog/rc.c
new file mode 100644
index 0000000..36631a6
--- /dev/null
+++ b/gnu/lib/libodialog/rc.c
@@ -0,0 +1,375 @@
+/*
+ * rc.c -- routines for processing the configuration file
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <dialog.h>
+#include "dialog.priv.h"
+#include "colors.h"
+#include "rc.h"
+
+
+static unsigned char *attr_to_str(int fg, int bg, int hl);
+static int str_to_attr(unsigned char *str, int *fg, int *bg, int *hl);
+static int parse_line(unsigned char *line, unsigned char **var, unsigned char **value);
+
+
+/*
+ * Create the configuration file
+ */
+void dialog_create_rc(unsigned char *filename)
+{
+ int i;
+ FILE *rc_file;
+
+ if ((rc_file = fopen(filename, "wt")) == NULL) {
+ fprintf(stderr, "\nError opening file for writing in create_rc().\n");
+ exit(-1);
+ }
+
+ fprintf(rc_file, "#\
+\n# Run-time configuration file for dialog\
+\n#\
+\n# Automatically generated by \"dialog --create-rc <file>\"\
+\n#\
+\n#\
+\n# Types of values:\
+\n#\
+\n# Number - <number>\
+\n# String - \"string\"\
+\n# Boolean - <ON|OFF>\
+\n# Attribute - (foreground,background,highlight?)\
+\n#\n\n");
+
+ /* Print an entry for each configuration variable */
+ for (i = 0; i < VAR_COUNT; i++) {
+ fprintf(rc_file, "\n# %s\n", vars[i].comment); /* print comment */
+ switch (vars[i].type) {
+ case VAL_INT:
+ fprintf(rc_file, "%s = %d\n", vars[i].name, *((int *) vars[i].var));
+ break;
+ case VAL_STR:
+ fprintf(rc_file, "%s = \"%s\"\n", vars[i].name, (unsigned char *) vars[i].var);
+ break;
+ case VAL_BOOL:
+ fprintf(rc_file, "%s = %s\n", vars[i].name, *((bool *) vars[i].var) ? "ON" : "OFF");
+ break;
+ case VAL_ATTR:
+ fprintf(rc_file, "%s = %s\n", vars[i].name, attr_to_str(((int *) vars[i].var)[0], ((int *) vars[i].var)[1], ((int *) vars[i].var)[2]));
+ break;
+ }
+ }
+
+ fclose(rc_file);
+}
+/* End of create_rc() */
+
+
+/*
+ * Parse the configuration file and set up variables
+ */
+int parse_rc(void)
+{
+ int i, l = 1, parse, fg, bg, hl;
+ unsigned char str[MAX_LEN+1], *var, *value, *tempptr;
+ FILE *rc_file;
+
+ /*
+ *
+ * At start, 'dialog' determines the settings to use as follows:
+ *
+ * a) if environment variable DIALOGRC is set, it's value determines the
+ * name of the configuration file.
+ *
+ * b) if the file in (a) can't be found, use the file $HOME/.dialogrc
+ * as the configuration file.
+ *
+ * c) if the file in (b) can't be found, use compiled in defaults.
+ *
+ */
+
+ if ((tempptr = getenv("DIALOGRC")) != NULL)
+ rc_file = fopen(tempptr, "rt");
+
+ if (tempptr == NULL || rc_file == NULL) { /* step (a) failed? */
+ /* try step (b) */
+ if ((tempptr = getenv("HOME")) == NULL)
+ return 0; /* step (b) failed, use default values */
+
+ if (tempptr[0] == '\0' || lastch(tempptr) == '/')
+ sprintf(str, "%s%s", tempptr, DIALOGRC);
+ else
+ sprintf(str, "%s/%s", tempptr, DIALOGRC);
+
+ if ((rc_file = fopen(str, "rt")) == NULL)
+ return 0; /* step (b) failed, use default values */
+ }
+
+ /* Scan each line and set variables */
+ while (fgets(str, MAX_LEN, rc_file) != NULL) {
+ if (lastch(str) != '\n') { /* ignore rest of file if line too long */
+ fprintf(stderr, "\nParse error: line %d of configuration file too long.\n", l);
+ fclose(rc_file);
+ return -1; /* parse aborted */
+ }
+ else {
+ lastch(str) = '\0';
+ parse = parse_line(str, &var, &value); /* parse current line */
+
+ switch (parse) {
+ case LINE_BLANK: /* ignore blank lines and comments */
+ case LINE_COMMENT:
+ break;
+ case LINE_OK:
+ /* search table for matching config variable name */
+ for (i = 0; i < VAR_COUNT && strcmp(vars[i].name, var); i++);
+
+ if (i == VAR_COUNT) { /* no match */
+ fprintf(stderr, "\nParse error: unknown variable at line %d of configuration file.\n", l);
+ return -1; /* parse aborted */
+ }
+ else { /* variable found in table, set run time variables */
+ switch (vars[i].type) {
+ case VAL_INT:
+ *((int *) vars[i].var) = atoi(value);
+ break;
+ case VAL_STR:
+ if (!isquote(value[0]) || !isquote(lastch(value)) || strlen(value) < 2) {
+ fprintf(stderr, "\nParse error: string value expected at line %d of configuration file.\n", l);
+ return -1; /* parse aborted */
+ }
+ else {
+ /* remove the (") quotes */
+ value++;
+ lastch(value) = '\0';
+ strcpy((unsigned char *) vars[i].var, value);
+ }
+ break;
+ case VAL_BOOL:
+ if (!strcasecmp(value, "ON"))
+ *((bool *) vars[i].var) = TRUE;
+ else if (!strcasecmp(value, "OFF"))
+ *((bool *) vars[i].var) = FALSE;
+ else {
+ fprintf(stderr, "\nParse error: boolean value expected at line %d of configuration file.\n", l);
+ return -1; /* parse aborted */
+ }
+ break;
+ case VAL_ATTR:
+ if (str_to_attr(value, &fg, &bg, &hl) == -1) {
+ fprintf(stderr, "\nParse error: attribute value expected at line %d of configuration file.\n", l);
+ return -1; /* parse aborted */
+ }
+ ((int *) vars[i].var)[0] = fg;
+ ((int *) vars[i].var)[1] = bg;
+ ((int *) vars[i].var)[2] = hl;
+ break;
+ }
+ }
+ break;
+ case LINE_ERROR:
+ fprintf(stderr, "\nParse error: syntax error at line %d of configuration file.\n", l);
+ return -1; /* parse aborted */
+ }
+ }
+
+ l++; /* next line */
+ }
+
+ fclose(rc_file);
+ return 0; /* parse successful */
+}
+/* End of parse_rc() */
+
+
+/*
+ * Convert an attribute to a string representation like this:
+ *
+ * "(foreground,background,highlight)"
+ */
+static unsigned char *attr_to_str(int fg, int bg, int hl)
+{
+ int i;
+ static unsigned char str[MAX_LEN+1];
+
+ strcpy(str, "(");
+ /* foreground */
+ for (i = 0; fg != color_names[i].value; i++);
+ strcat(str, color_names[i].name);
+ strcat(str, ",");
+
+ /* background */
+ for (i = 0; bg != color_names[i].value; i++);
+ strcat(str, color_names[i].name);
+
+ /* highlight */
+ strcat(str, hl ? ",ON)" : ",OFF)");
+
+ return str;
+}
+/* End of attr_to_str() */
+
+
+/*
+ * Extract the foreground, background and highlight values from an attribute
+ * represented as a string in this form:
+ *
+ * "(foreground,background,highlight)"
+ */
+static int str_to_attr(unsigned char *str, int *fg, int *bg, int *hl)
+{
+ int i = 0, j, get_fg = 1;
+ unsigned char tempstr[MAX_LEN+1], *part;
+
+ if (str[0] != '(' || lastch(str) != ')')
+ return -1; /* invalid representation */
+
+ /* remove the parenthesis */
+ strcpy(tempstr, str + 1);
+ lastch(tempstr) = '\0';
+
+
+ /* get foreground and background */
+
+ while (1) {
+ /* skip white space before fg/bg string */
+ while (whitespace(tempstr[i]) && tempstr[i] != '\0') i++;
+ if (tempstr[i] == '\0')
+ return -1; /* invalid representation */
+ part = tempstr + i; /* set 'part' to start of fg/bg string */
+
+ /* find end of fg/bg string */
+ while(!whitespace(tempstr[i]) && tempstr[i] != ',' && tempstr[i] != '\0') i++;
+
+ if (tempstr[i] == '\0')
+ return -1; /* invalid representation */
+ else if (whitespace(tempstr[i])) { /* not yet ',' */
+ tempstr[i++] = '\0';
+
+ /* skip white space before ',' */
+ while(whitespace(tempstr[i]) && tempstr[i] != '\0') i++;
+
+ if (tempstr[i] != ',')
+ return -1; /* invalid representation */
+ }
+
+ tempstr[i++] = '\0'; /* skip the ',' */
+ for (j = 0; j < COLOR_COUNT && strcasecmp(part, color_names[j].name); j++);
+ if (j == COLOR_COUNT) /* invalid color name */
+ return -1;
+ if (get_fg) {
+ *fg = color_names[j].value;
+ get_fg = 0; /* next we have to get the background */
+ }
+ else {
+ *bg = color_names[j].value;
+ break;
+ }
+ } /* got foreground and background */
+
+
+ /* get highlight */
+
+ /* skip white space before highlight string */
+ while (whitespace(tempstr[i]) && tempstr[i] != '\0') i++;
+ if (tempstr[i] == '\0')
+ return -1; /* invalid representation */
+ part = tempstr + i; /* set 'part' to start of highlight string */
+
+ /* trim trailing white space from highlight string */
+ i = strlen(part) - 1;
+ while(whitespace(part[i])) i--;
+ part[i+1] = '\0';
+
+ if (!strcasecmp(part, "ON"))
+ *hl = TRUE;
+ else if (!strcasecmp(part, "OFF"))
+ *hl = FALSE;
+ else
+ return -1; /* invalid highlight value */
+
+ return 0;
+}
+/* End of str_to_attr() */
+
+
+/*
+ * Parse a line in the configuration file
+ *
+ * Each line is of the form: "variable = value". On exit, 'var' will contain
+ * the variable name, and 'value' will contain the value string.
+ *
+ * Return values:
+ *
+ * LINE_BLANK - line is blank
+ * LINE_COMMENT - line is comment
+ * LINE_OK - line is ok
+ * LINE_ERROR - syntax error in line
+ */
+static int parse_line(unsigned char *line, unsigned char **var, unsigned char **value)
+{
+ int i = 0;
+
+ /* ignore white space at beginning of line */
+ while(whitespace(line[i]) && line[i] != '\0') i++;
+
+ if (line[i] == '\0') /* line is blank */
+ return LINE_BLANK;
+ else if (line[i] == '#') /* line is comment */
+ return LINE_COMMENT;
+ else if (line[i] == '=') /* variables names can't strart with a '=' */
+ return LINE_ERROR;
+
+ /* set 'var' to variable name */
+ *var = line + i++; /* skip to next character */
+
+ /* find end of variable name */
+ while(!whitespace(line[i]) && line[i] != '=' && line[i] != '\0') i++;
+
+ if (line[i] == '\0') /* syntax error */
+ return LINE_ERROR;
+ else if (line[i] == '=')
+ line[i++] = '\0';
+ else {
+ line[i++] = '\0';
+
+ /* skip white space before '=' */
+ while(whitespace(line[i]) && line[i] != '\0') i++;
+
+ if (line[i] != '=') /* syntax error */
+ return LINE_ERROR;
+ else
+ i++; /* skip the '=' */
+ }
+
+ /* skip white space after '=' */
+ while(whitespace(line[i]) && line[i] != '\0') i++;
+
+ if (line[i] == '\0')
+ return LINE_ERROR;
+ else
+ *value = line + i; /* set 'value' to value string */
+
+ /* trim trailing white space from 'value' */
+ i = strlen(*value) - 1;
+ while(whitespace((*value)[i])) i--;
+ (*value)[i+1] = '\0';
+
+ return LINE_OK; /* no syntax error in line */
+}
+/* End of parse_line() */
diff --git a/gnu/lib/libodialog/rc.h b/gnu/lib/libodialog/rc.h
new file mode 100644
index 0000000..fc19d03
--- /dev/null
+++ b/gnu/lib/libodialog/rc.h
@@ -0,0 +1,222 @@
+/*
+ * rc.h -- declarations for configuration file processing
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#define DIALOGRC ".dialogrc"
+#define VAR_LEN 30
+#define COMMENT_LEN 70
+
+/* Types of values */
+#define VAL_INT 0
+#define VAL_STR 1
+#define VAL_BOOL 2
+#define VAL_ATTR 3
+
+/* Type of line in configuration file */
+#define LINE_BLANK 2
+#define LINE_COMMENT 1
+#define LINE_OK 0
+#define LINE_ERROR -1
+
+/* number of configuration variables */
+#define VAR_COUNT (sizeof(vars) / sizeof(vars_st))
+
+/* check if character is white space */
+#define whitespace(c) (c == ' ' || c == '\t')
+
+/* check if character is string quoting characters */
+#define isquote(c) (c == '"' || c == '\'')
+
+/* get last character of string */
+#define lastch(str) str[strlen(str)-1]
+
+/*
+ * Configuration variables
+ */
+typedef struct {
+ unsigned char name[VAR_LEN]; /* name of configuration variable as in DIALOGRC */
+ void *var; /* address of actually variable to change */
+ int type; /* type of value */
+ unsigned char comment[COMMENT_LEN]; /* comment to put in "rc" file */
+} vars_st;
+
+vars_st vars[] = {
+ { "use_shadow",
+ &use_shadow,
+ VAL_BOOL,
+ "Shadow dialog boxes? This also turns on color." },
+
+ { "use_colors",
+ &use_colors,
+ VAL_BOOL,
+ "Turn color support ON or OFF" },
+
+ { "screen_color",
+ color_table[0],
+ VAL_ATTR,
+ "Screen color" },
+
+ { "shadow_color",
+ color_table[1],
+ VAL_ATTR,
+ "Shadow color" },
+
+ { "dialog_color",
+ color_table[2],
+ VAL_ATTR,
+ "Dialog box color" },
+
+ { "title_color",
+ color_table[3],
+ VAL_ATTR,
+ "Dialog box title color" },
+
+ { "border_color",
+ color_table[4],
+ VAL_ATTR,
+ "Dialog box border color" },
+
+ { "button_active_color",
+ color_table[5],
+ VAL_ATTR,
+ "Active button color" },
+
+ { "button_inactive_color",
+ color_table[6],
+ VAL_ATTR,
+ "Inactive button color" },
+
+ { "button_key_active_color",
+ color_table[7],
+ VAL_ATTR,
+ "Active button key color" },
+
+ { "button_key_inactive_color",
+ color_table[8],
+ VAL_ATTR,
+ "Inactive button key color" },
+
+ { "button_label_active_color",
+ color_table[9],
+ VAL_ATTR,
+ "Active button label color" },
+
+ { "button_label_inactive_color",
+ color_table[10],
+ VAL_ATTR,
+ "Inactive button label color" },
+
+ { "inputbox_color",
+ color_table[11],
+ VAL_ATTR,
+ "Input box color" },
+
+ { "inputbox_border_color",
+ color_table[12],
+ VAL_ATTR,
+ "Input box border color" },
+
+ { "searchbox_color",
+ color_table[13],
+ VAL_ATTR,
+ "Search box color" },
+
+ { "searchbox_title_color",
+ color_table[14],
+ VAL_ATTR,
+ "Search box title color" },
+
+ { "searchbox_border_color",
+ color_table[15],
+ VAL_ATTR,
+ "Search box border color" },
+
+ { "position_indicator_color",
+ color_table[16],
+ VAL_ATTR,
+ "File position indicator color" },
+
+ { "menubox_color",
+ color_table[17],
+ VAL_ATTR,
+ "Menu box color" },
+
+ { "menubox_border_color",
+ color_table[18],
+ VAL_ATTR,
+ "Menu box border color" },
+
+ { "item_color",
+ color_table[19],
+ VAL_ATTR,
+ "Item color" },
+
+ { "item_selected_color",
+ color_table[20],
+ VAL_ATTR,
+ "Selected item color" },
+
+ { "tag_color",
+ color_table[21],
+ VAL_ATTR,
+ "Tag color" },
+
+ { "tag_selected_color",
+ color_table[22],
+ VAL_ATTR,
+ "Selected tag color" },
+
+ { "tag_key_color",
+ color_table[23],
+ VAL_ATTR,
+ "Tag key color" },
+
+ { "tag_key_selected_color",
+ color_table[24],
+ VAL_ATTR,
+ "Selected tag key color" },
+
+ { "check_color",
+ color_table[25],
+ VAL_ATTR,
+ "Check box color" },
+
+ { "check_selected_color",
+ color_table[26],
+ VAL_ATTR,
+ "Selected check box color" },
+
+ { "uarrow_color",
+ color_table[27],
+ VAL_ATTR,
+ "Up arrow color" },
+
+ { "darrow_color",
+ color_table[28],
+ VAL_ATTR,
+ "Down arrow color" }
+}; /* vars */
+
+
+
+/*
+ * Routines to process configuration file
+ */
+int parse_rc(void);
diff --git a/gnu/lib/libodialog/textbox.c b/gnu/lib/libodialog/textbox.c
new file mode 100644
index 0000000..19a13bb
--- /dev/null
+++ b/gnu/lib/libodialog/textbox.c
@@ -0,0 +1,699 @@
+/*
+ * textbox.c -- implements the text box
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dialog.h>
+#include "dialog.priv.h"
+
+
+static void back_lines(int n);
+static void print_page(WINDOW *win, int height, int width);
+static void print_line(WINDOW *win, int row, int width);
+static unsigned char *get_line(void);
+static int get_search_term(WINDOW *win, unsigned char *search_term, int height, int width);
+static void print_position(WINDOW *win, int height, int width);
+
+
+static int hscroll = 0, fd, file_size, bytes_read, begin_reached = 1,
+ end_reached = 0, page_length;
+static unsigned char *buf, *page;
+
+
+/*
+ * Display text from a file in a dialog box.
+ */
+int dialog_textbox(unsigned char *title, unsigned char *file, int height, int width)
+{
+ int i, x, y, cur_x, cur_y, fpos, key = 0, dir, temp, temp1;
+#ifdef HAVE_NCURSES
+ int passed_end;
+#endif
+ unsigned char search_term[MAX_LEN+1], *tempptr, *found;
+ WINDOW *dialog, *text;
+
+ if (height < 0 || width < 0) {
+ fprintf(stderr, "\nAutosizing is impossible in dialog_textbox().\n");
+ return(-1);
+ }
+
+ search_term[0] = '\0'; /* no search term entered yet */
+
+ /* Open input file for reading */
+ if ((fd = open(file, O_RDONLY)) == -1) {
+ fprintf(stderr, "\nCan't open input file <%s>in dialog_textbox().\n", file);
+ return(-1);
+ }
+ /* Get file size. Actually, 'file_size' is the real file size - 1,
+ since it's only the last byte offset from the beginning */
+ if ((file_size = lseek(fd, 0, SEEK_END)) == -1) {
+ fprintf(stderr, "\nError getting file size in dialog_textbox().\n");
+ return(-1);
+ }
+ /* Restore file pointer to beginning of file after getting file size */
+ if (lseek(fd, 0, SEEK_SET) == -1) {
+ fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+ return(-1);
+ }
+ /* Allocate space for read buffer */
+ if ((buf = malloc(BUF_SIZE+1)) == NULL) {
+ endwin();
+ fprintf(stderr, "\nCan't allocate memory in dialog_textbox().\n");
+ exit(-1);
+ }
+ if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
+ fprintf(stderr, "\nError reading file in dialog_textbox().\n");
+ return(-1);
+ }
+ buf[bytes_read] = '\0'; /* mark end of valid data */
+ page = buf; /* page is pointer to start of page to be displayed */
+
+ if (width > COLS)
+ width = COLS;
+ if (height > LINES)
+ height = LINES;
+ /* center dialog box on screen */
+ x = DialogX ? DialogX : (COLS - width)/2;
+ y = DialogY ? DialogY : (LINES - height)/2;
+
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(stdscr, y, x, height, width);
+#endif
+ dialog = newwin(height, width, y, x);
+ if (dialog == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width,y,x);
+ exit(1);
+ }
+ keypad(dialog, TRUE);
+
+ /* Create window for text region, used for scrolling text */
+/* text = newwin(height-4, width-2, y+1, x+1); */
+ text = subwin(dialog, height-4, width-2, y+1, x+1);
+ if (text == NULL) {
+ endwin();
+ fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", height-4,width-2,y+1,x+1);
+ exit(1);
+ }
+ keypad(text, TRUE);
+
+ draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+
+ wattrset(dialog, border_attr);
+ wmove(dialog, height-3, 0);
+ waddch(dialog, ACS_LTEE);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dialog_attr);
+ waddch(dialog, ACS_RTEE);
+ wmove(dialog, height-2, 1);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ' ');
+
+ if (title != NULL) {
+ wattrset(dialog, title_attr);
+ wmove(dialog, 0, (width - strlen(title))/2 - 1);
+ waddch(dialog, ' ');
+ waddstr(dialog, title);
+ waddch(dialog, ' ');
+ }
+ display_helpline(dialog, height-1, width);
+
+ print_button(dialog, " OK ", height-2, width/2-6, TRUE);
+ wnoutrefresh(dialog);
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+
+ /* Print first page of text */
+ attr_clear(text, height-4, width-2, dialog_attr);
+ print_page(text, height-4, width-2);
+ print_position(dialog, height, width);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+
+ while ((key != ESC) && (key != '\n') && (key != '\r') && (key != ' ')) {
+ key = wgetch(dialog);
+ switch (key) {
+ case 'E': /* Exit */
+ case 'e':
+ delwin(dialog);
+ free(buf);
+ close(fd);
+ return 0;
+ case 'g': /* First page */
+ case KEY_HOME:
+ if (!begin_reached) {
+ begin_reached = 1;
+ /* First page not in buffer? */
+ if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+ exit(-1);
+ }
+ if (fpos > bytes_read) { /* Yes, we have to read it in */
+ if (lseek(fd, 0, SEEK_SET) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+ exit(-1);
+ }
+ if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError reading file in dialog_textbox().\n");
+ exit(-1);
+ }
+ buf[bytes_read] = '\0';
+ }
+ page = buf;
+ print_page(text, height-4, width-2);
+ print_position(dialog, height, width);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ break;
+ case 'G': /* Last page */
+#ifdef HAVE_NCURSES
+ case KEY_END:
+#endif
+ end_reached = 1;
+ /* Last page not in buffer? */
+ if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+ exit(-1);
+ }
+ if (fpos < file_size) { /* Yes, we have to read it in */
+ if (lseek(fd, -BUF_SIZE, SEEK_END) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+ exit(-1);
+ }
+ if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError reading file in dialog_textbox().\n");
+ exit(-1);
+ }
+ buf[bytes_read] = '\0';
+ }
+ page = buf + bytes_read;
+ back_lines(height-4);
+ print_page(text, height-4, width-2);
+ print_position(dialog, height, width);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ break;
+ case 'K': /* Previous line */
+ case 'k':
+ case '\020': /* ^P */
+ case KEY_UP:
+ if (!begin_reached) {
+ back_lines(page_length+1);
+#ifdef HAVE_NCURSES
+ /* We don't call print_page() here but use scrolling to ensure
+ faster screen update. However, 'end_reached' and 'page_length'
+ should still be updated, and 'page' should point to start of
+ next page. This is done by calling get_line() in the following
+ 'for' loop. */
+ scrollok(text, TRUE);
+ wscrl(text, -1); /* Scroll text region down one line */
+ scrollok(text, FALSE);
+ page_length = 0;
+ passed_end = 0;
+ for (i = 0; i < height-4; i++) {
+ if (!i) {
+ print_line(text, 0, width-2); /* print first line of page */
+ wnoutrefresh(text);
+ }
+ else
+ get_line(); /* Called to update 'end_reached' and 'page' */
+ if (!passed_end)
+ page_length++;
+ if (end_reached && !passed_end)
+ passed_end = 1;
+ }
+#else
+ print_page(text, height-4, width-2);
+#endif
+ print_position(dialog, height, width);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ break;
+ case 'B': /* Previous page */
+ case 'b':
+ case KEY_PPAGE:
+ if (!begin_reached) {
+ back_lines(page_length + height-4);
+ print_page(text, height-4, width-2);
+ print_position(dialog, height, width);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ break;
+ case 'J': /* Next line */
+ case 'j':
+ case '\016': /* ^N */
+ case KEY_DOWN:
+ if (!end_reached) {
+ begin_reached = 0;
+ scrollok(text, TRUE);
+ scroll(text); /* Scroll text region up one line */
+ scrollok(text, FALSE);
+ print_line(text, height-5, width-2);
+#ifndef HAVE_NCURSES
+ wmove(text, height-5, 0);
+ waddch(text, ' ');
+ wmove(text, height-5, width-3);
+ waddch(text, ' ');
+#endif
+ wnoutrefresh(text);
+ print_position(dialog, height, width);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ break;
+ case 'F': /* Next page */
+ case 'f':
+ case KEY_NPAGE:
+ if (!end_reached) {
+ begin_reached = 0;
+ print_page(text, height-4, width-2);
+ print_position(dialog, height, width);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ break;
+ case '0': /* Beginning of line */
+ case 'H': /* Scroll left */
+ case 'h':
+ case KEY_LEFT:
+ if (hscroll > 0) {
+ if (key == '0')
+ hscroll = 0;
+ else
+ hscroll--;
+ /* Reprint current page to scroll horizontally */
+ back_lines(page_length);
+ print_page(text, height-4, width-2);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ break;
+ case 'L': /* Scroll right */
+ case 'l':
+ case KEY_RIGHT:
+ if (hscroll < MAX_LEN) {
+ hscroll++;
+ /* Reprint current page to scroll horizontally */
+ back_lines(page_length);
+ print_page(text, height-4, width-2);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ break;
+ case '/': /* Forward search */
+ case 'n': /* Repeat forward search */
+ case '?': /* Backward search */
+ case 'N': /* Repeat backward search */
+ /* set search direction */
+ dir = (key == '/' || key == 'n') ? 1 : 0;
+ if (dir ? !end_reached : !begin_reached) {
+ if (key == 'n' || key == 'N') {
+ if (search_term[0] == '\0') { /* No search term yet */
+ fprintf(stderr, "\a"); /* beep */
+ break;
+ }
+ }
+ else /* Get search term from user */
+ if (get_search_term(text, search_term, height-4, width-2) == -1) {
+ /* ESC pressed in get_search_term(). Reprint page to clear box */
+ wattrset(text, dialog_attr);
+ back_lines(page_length);
+ print_page(text, height-4, width-2);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ break;
+ }
+ /* Save variables for restoring in case search term can't be found */
+ tempptr = page;
+ temp = begin_reached;
+ temp1 = end_reached;
+ if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+ exit(-1);
+ }
+ fpos -= bytes_read;
+ /* update 'page' to point to next (previous) line before
+ forward (backward) searching */
+ back_lines(dir ? page_length-1 : page_length+1);
+ found = NULL;
+ if (dir) /* Forward search */
+ while((found = strstr(get_line(), search_term)) == NULL) {
+ if (end_reached)
+ break;
+ }
+ else /* Backward search */
+ while((found = strstr(get_line(), search_term)) == NULL) {
+ if (begin_reached)
+ break;
+ back_lines(2);
+ }
+ if (found == NULL) { /* not found */
+ fprintf(stderr, "\a"); /* beep */
+ /* Restore program state to that before searching */
+ if (lseek(fd, fpos, SEEK_SET) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
+ exit(-1);
+ }
+ if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError reading file in dialog_textbox().\n");
+ exit(-1);
+ }
+ buf[bytes_read] = '\0';
+ page = tempptr;
+ begin_reached = temp;
+ end_reached = temp1;
+ /* move 'page' to point to start of current page in order to
+ re-print current page. Note that 'page' always points to
+ start of next page, so this is necessary */
+ back_lines(page_length);
+ }
+ else /* Search term found */
+ back_lines(1);
+ /* Reprint page */
+ wattrset(text, dialog_attr);
+ print_page(text, height-4, width-2);
+ if (found != NULL)
+ print_position(dialog, height, width);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ else /* no need to find */
+ fprintf(stderr, "\a"); /* beep */
+ break;
+ case ESC:
+ break;
+ case KEY_F(1):
+ display_helpfile();
+ break;
+ }
+ }
+
+ delwin(dialog);
+ free(buf);
+ close(fd);
+ return (key == ESC ? -1 : 0);
+}
+/* End of dialog_textbox() */
+
+
+/*
+ * Go back 'n' lines in text file. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+ int i, fpos;
+
+ begin_reached = 0;
+ /* We have to distinguish between end_reached and !end_reached since at end
+ of file, the line is not ended by a '\n'. The code inside 'if' basically
+ does a '--page' to move one character backward so as to skip '\n' of the
+ previous line */
+ if (!end_reached) {
+ /* Either beginning of buffer or beginning of file reached? */
+ if (page == buf) {
+ if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in back_lines().\n");
+ exit(-1);
+ }
+ if (fpos > bytes_read) { /* Not beginning of file yet */
+ /* We've reached beginning of buffer, but not beginning of file yet,
+ so read previous part of file into buffer. Note that we only
+ move backward for BUF_SIZE/2 bytes, but not BUF_SIZE bytes to
+ avoid re-reading again in print_page() later */
+ /* Really possible to move backward BUF_SIZE/2 bytes? */
+ if (fpos < BUF_SIZE/2 + bytes_read) {
+ /* No, move less then */
+ if (lseek(fd, 0, SEEK_SET) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in back_lines().\n");
+ exit(-1);
+ }
+ page = buf + fpos - bytes_read;
+ }
+ else { /* Move backward BUF_SIZE/2 bytes */
+ if (lseek(fd, -(BUF_SIZE/2 + bytes_read), SEEK_CUR) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in back_lines().\n");
+ exit(-1);
+ }
+ page = buf + BUF_SIZE/2;
+ }
+ if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError reading file in back_lines().\n");
+ exit(-1);
+ }
+ buf[bytes_read] = '\0';
+ }
+ else { /* Beginning of file reached */
+ begin_reached = 1;
+ return;
+ }
+ }
+ if (*(--page) != '\n') { /* '--page' here */
+ /* Something's wrong... */
+ endwin();
+ fprintf(stderr, "\nInternal error in back_lines().\n");
+ exit(-1);
+ }
+ }
+
+ /* Go back 'n' lines */
+ for (i = 0; i < n; i++)
+ do {
+ if (page == buf) {
+ if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in back_lines().\n");
+ exit(-1);
+ }
+ if (fpos > bytes_read) {
+ /* Really possible to move backward BUF_SIZE/2 bytes? */
+ if (fpos < BUF_SIZE/2 + bytes_read) {
+ /* No, move less then */
+ if (lseek(fd, 0, SEEK_SET) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in back_lines().\n");
+ exit(-1);
+ }
+ page = buf + fpos - bytes_read;
+ }
+ else { /* Move backward BUF_SIZE/2 bytes */
+ if (lseek(fd, -(BUF_SIZE/2 + bytes_read), SEEK_CUR) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in back_lines().\n");
+ exit(-1);
+ }
+ page = buf + BUF_SIZE/2;
+ }
+ if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError reading file in back_lines().\n");
+ exit(-1);
+ }
+ buf[bytes_read] = '\0';
+ }
+ else { /* Beginning of file reached */
+ begin_reached = 1;
+ return;
+ }
+ }
+ } while (*(--page) != '\n');
+ page++;
+}
+/* End of back_lines() */
+
+
+/*
+ * Print a new page of text. Called by dialog_textbox().
+ */
+static void print_page(WINDOW *win, int height, int width)
+{
+ int i, passed_end = 0;
+
+ page_length = 0;
+ for (i = 0; i < height; i++) {
+ print_line(win, i, width);
+ if (!passed_end)
+ page_length++;
+ if (end_reached && !passed_end)
+ passed_end = 1;
+ }
+ wnoutrefresh(win);
+}
+/* End of print_page() */
+
+
+/*
+ * Print a new line of text. Called by dialog_textbox() and print_page().
+ */
+static void print_line(WINDOW *win, int row, int width)
+{
+ int i, y, x;
+ unsigned char *line;
+
+ line = get_line();
+ line += MIN(strlen(line),hscroll); /* Scroll horizontally */
+ wmove(win, row, 0); /* move cursor to correct line */
+ waddch(win,' ');
+#ifdef HAVE_NCURSES
+ waddnstr(win, line, MIN(strlen(line),width-2));
+#else
+ line[MIN(strlen(line),width-2)] = '\0';
+ waddstr(win, line);
+#endif
+
+ getyx(win, y, x);
+ /* Clear 'residue' of previous line */
+ for (i = 0; i < width-x; i++)
+ waddch(win, ' ');
+}
+/* End of print_line() */
+
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static unsigned char *get_line(void)
+{
+ int i = 0, fpos;
+ static unsigned char line[MAX_LEN+1];
+
+ end_reached = 0;
+ while (*page != '\n') {
+ if (*page == '\0') { /* Either end of file or end of buffer reached */
+ if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in get_line().\n");
+ exit(-1);
+ }
+ if (fpos < file_size) { /* Not end of file yet */
+ /* We've reached end of buffer, but not end of file yet, so read next
+ part of file into buffer */
+ if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError reading file in get_line().\n");
+ exit(-1);
+ }
+ buf[bytes_read] = '\0';
+ page = buf;
+ }
+ else {
+ if (!end_reached)
+ end_reached = 1;
+ break;
+ }
+ }
+ else
+ if (i < MAX_LEN)
+ line[i++] = *(page++);
+ else {
+ if (i == MAX_LEN) /* Truncate lines longer than MAX_LEN characters */
+ line[i++] = '\0';
+ page++;
+ }
+ }
+ if (i <= MAX_LEN)
+ line[i] = '\0';
+ if (!end_reached)
+ page++; /* move pass '\n' */
+
+ return line;
+}
+/* End of get_line() */
+
+
+/*
+ * Display a dialog box and get the search term from user
+ */
+static int get_search_term(WINDOW *win, unsigned char *search_term, int height, int width)
+{
+ int x, y, key = 0, first,
+ box_height = 3, box_width = 30;
+
+ x = (width - box_width)/2;
+ y = (height - box_height)/2;
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(win, y, x, box_height, box_width);
+#endif
+ draw_box(win, y, x, box_height, box_width, dialog_attr, searchbox_border_attr);
+ wattrset(win, searchbox_title_attr);
+ wmove(win, y, x+box_width/2-4);
+ waddstr(win, " Search ");
+ wattrset(win, dialog_attr);
+
+ search_term[0] = '\0';
+
+ first = 1;
+ while (key != ESC) {
+ key = line_edit(win, y+1, x+1, -1, box_width-2, searchbox_attr, first, search_term, 0);
+ first = 0;
+ switch (key) {
+ case '\n':
+ if (search_term[0] != '\0')
+ return 0;
+ break;
+ case ESC:
+ break;
+ }
+ }
+
+ return -1; /* ESC pressed */
+}
+/* End of get_search_term() */
+
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW *win, int height, int width)
+{
+ int fpos, percent;
+
+ if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
+ endwin();
+ fprintf(stderr, "\nError moving file pointer in print_position().\n");
+ exit(-1);
+ }
+ wattrset(win, position_indicator_attr);
+ percent = !file_size ? 100 : ((fpos-bytes_read+page-buf)*100)/file_size;
+ wmove(win, height-3, width-9);
+ wprintw(win, "(%3d%%)", percent);
+}
+/* End of print_position() */
diff --git a/gnu/lib/libodialog/tree.c b/gnu/lib/libodialog/tree.c
new file mode 100644
index 0000000..ceacf05
--- /dev/null
+++ b/gnu/lib/libodialog/tree.c
@@ -0,0 +1,1133 @@
+/*
+ * tree.c -- implements the 'tree' interface element for libdialog
+ *
+ * Author: Anatoly A. Orehovsky (tolik@mpeks.tomsk.su)
+ *
+ * Copyright (c) 1997, Anatoly A. Orehovsky
+ * 09/28/98 - patched by Anatoly A. Orehovsky (smart_tree())
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdlib.h>
+#include <strings.h>
+#include <stdio.h>
+#include <dialog.h>
+#include "dialog.priv.h"
+#include <ncurses.h>
+
+/* static utils for make tree */
+struct leaf {
+ unsigned char *name; /* name of leaf */
+ unsigned char *branches; /* branches that going by leaf */
+ unsigned char slip; /* slip of leaf*/
+ int shift; /* shift relative root of tree */
+};
+
+static int mk_slip(struct leaf array[], int arr_size,
+ int number, int shift);
+
+/* make tree from file
+ *
+ * filename - name of file with like find(1) output
+ * p_names - pointer to array of strings
+ * p_size - pointer to size of array
+ * FS - fields separator
+ * p_array - pointer to array of leafs
+ *
+ * return values:
+ * 0 - ok and names by p_names, size by p_size, array by p_array set
+ * -1 - memory allocation error (errno set)
+ */
+
+static int mk_ftree(char *filename,
+ unsigned char ***p_names, int *p_size, unsigned char FS,
+ struct leaf **p_array);
+
+/* make tree from array
+ *
+ * names - array of strings
+ * size - size of array
+ * FS - fields separator
+ * p_array - pointer to array of leafs
+ *
+ * return values:
+ * 0 - ok and array by p_array set
+ * -1 - memory allocation error (errno set)
+ */
+
+static int mk_tree(unsigned char **names, int size, unsigned char FS,
+ struct leaf **p_array);
+
+/* free memory from tree (leafs)
+ *
+ * return values:
+ * nothing
+ */
+
+static void free_leafs(struct leaf *array, int size);
+
+/* free memory from source data for tree (names)
+ *
+ * return values:
+ * if 0 <= choice <= size - pointer to name from names,
+ * and memory for name not released (must be freed later)
+ * else - NULL (recomended choice -1 for it)
+ */
+
+static unsigned char *free_names(unsigned char **names,
+ int size, int choice);
+
+/* end of static utils for make tree */
+
+/* static utils for ftree */
+
+/* control struct for queue */
+struct queue {
+ int size; /* size of queue */
+ struct m_queue *first; /* begin of queue */
+ struct m_queue *last; /* end of queue */
+};
+
+/* queue member */
+struct m_queue {
+ void *pointer; /* queue member */
+ struct m_queue *next; /* next queue member */
+};
+
+/* init struct queue by zeros */
+static void init_queue(struct queue *queue);
+
+/* add pointer to queue */
+/* return - pointer or NULL if error */
+static void *p2_queue(struct queue *queue, void *pointer);
+
+/* get first from queue */
+/* return - pointer or NULL if queue is empty */
+static void *first_queue(struct queue *queue);
+
+/* make zero terminated array from queue */
+/* return - pointer to array or NULL if error */
+static void **q2arr(struct queue *queue, int depth);
+
+/* smart_tree (for like find(1) with -d flag output compliance) */
+/* return - not NULL or NULL if malloc error */
+static unsigned char *smart_tree(struct queue *queue, unsigned char FS,
+ unsigned char *current,
+ unsigned char *prev);
+
+/* end of static utils for ftree */
+
+/* static utils for saved_tree */
+
+/* saved values for unique tree */
+struct saved_tree {
+ unsigned char **names; /* names + */
+ int size; /* size + */
+ unsigned char FS; /* FS + */
+ int height; /* height + */
+ int width; /* width + */
+ int menu_height; /* menu_height - unique for treebox ? */
+ int ch; /* saved ch - choice */
+ int sc; /* saved sc - scroll */
+};
+
+/* search saved tree within queue */
+/* return - struct saved_tree * or NULL if not found */
+static struct saved_tree *search_saved_tree(struct queue *queue,
+ unsigned char **names,
+ int size,
+ unsigned char FS,
+ int height,
+ int width,
+ int menu_height);
+
+/* end of static utils for saved_tree */
+
+static void print_item(WINDOW *win, struct leaf item, int choice, int selected);
+
+static void print_position(WINDOW *win, int x, int y,
+ int cur_pos, int size);
+
+static int menu_width, item_x;
+
+static int dialog_treemenu(unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ int item_no, struct leaf items[],
+ int *result,
+ int *ch, int *sc);
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+static
+int dialog_treemenu(unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ int item_no, struct leaf items[],
+ int *result,
+ int *ch, int *sc)
+{
+ int i, j, x, y, cur_x, cur_y, box_x, box_y, key = 0, button = 0, choice = 0,
+ l, scroll = 0, max_choice, redraw_menu = FALSE;
+ WINDOW *dialog, *menu;
+
+ if (ch) /* restore menu item info */
+ choice = *ch;
+ if (sc)
+ scroll = *sc;
+
+ max_choice = MIN(menu_height, item_no);
+
+ item_x = 0;
+ /* Find length of longest item in order to center menu */
+ for (i = 0; i < item_no; i++) {
+ l = strlen(items[i].name) + strlen(items[i].branches) * 4 + 4;
+ item_x = MAX(item_x, l);
+ }
+
+ if (height < 0)
+ height = strheight(prompt)+menu_height+4+2;
+ if (width < 0) {
+ i = strwidth(prompt);
+ j = ((title != NULL) ? strwidth(title) : 0);
+ width = MAX(i,j);
+ width = MAX(width,item_x+4)+4;
+ }
+ width = MAX(width,24);
+
+ if (width > COLS)
+ width = COLS;
+ if (height > LINES)
+ height = LINES;
+ /* center dialog box on screen */
+ x = (COLS - width)/2;
+ y = (LINES - height)/2;
+
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(stdscr, y, x, height, width);
+#endif
+ dialog = newwin(height, width, y, x);
+ if (dialog == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width,y,x);
+ exit(1);
+ }
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+ wattrset(dialog, border_attr);
+ wmove(dialog, height-3, 0);
+ waddch(dialog, ACS_LTEE);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dialog_attr);
+ waddch(dialog, ACS_RTEE);
+ wmove(dialog, height-2, 1);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ' ');
+
+ if (title != NULL) {
+ wattrset(dialog, title_attr);
+ wmove(dialog, 0, (width - strlen(title))/2 - 1);
+ waddch(dialog, ' ');
+ waddstr(dialog, title);
+ waddch(dialog, ' ');
+ }
+ wattrset(dialog, dialog_attr);
+ wmove(dialog, 1, 2);
+ print_autowrap(dialog, prompt, height-1, width-2, width, 1, 2, TRUE, FALSE);
+
+ menu_width = width-6;
+ getyx(dialog, cur_y, cur_x);
+ box_y = cur_y + 1;
+ box_x = (width - menu_width)/2 - 1;
+
+ /* create new window for the menu */
+ menu = subwin(dialog, menu_height, menu_width, y + box_y + 1, x + box_x + 1);
+ if (menu == NULL) {
+ endwin();
+ fprintf(stderr, "\nsubwin(dialog,%d,%d,%d,%d) failed, maybe wrong dims\n", menu_height,menu_width,y+box_y+1,x+box_x+1);
+ exit(1);
+ }
+ keypad(menu, TRUE);
+
+ /* draw a box around the menu items */
+ draw_box(dialog, box_y, box_x, menu_height+2, menu_width+2, menubox_border_attr, menubox_attr);
+
+ item_x = 1;
+
+ /* Print the menu */
+ for (i = 0; i < max_choice; i++)
+ print_item(menu, items[(scroll+i)], i, i == choice);
+ wnoutrefresh(menu);
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, item_x, cur_x, cur_y);
+ print_position(dialog, box_x+menu_width, box_y+menu_height, scroll+choice, item_no);
+
+ display_helpline(dialog, height-1, width);
+
+ x = width/2-11;
+ y = height-2;
+ print_button(dialog, "Cancel", y, x+14, FALSE);
+ print_button(dialog, " OK ", y, x, TRUE);
+
+ wrefresh(dialog);
+
+ while (key != ESC) {
+ key = wgetch(dialog);
+ /* Check if key pressed matches first character of any item tag in menu */
+
+ if (key == KEY_UP || key == KEY_DOWN || key == '-' || key == '+') {
+ if (key == KEY_UP || key == '-') {
+ if (!choice) {
+ if (scroll) {
+#ifdef BROKEN_WSCRL
+ /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation
+ violation when scrolling windows of height = 4, so scrolling is not
+ used for now */
+ scroll--;
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ /* Reprint menu to scroll down */
+ for (i = 0; i < max_choice; i++)
+ print_item(menu, items[(scroll+i)], i, i == choice);
+
+#else
+
+ /* Scroll menu down */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ if (menu_height > 1) {
+ /* De-highlight current first item before scrolling down */
+ print_item(menu, items[scroll], 0, FALSE);
+ scrollok(menu, TRUE);
+ wscrl(menu, -1);
+ scrollok(menu, FALSE);
+ }
+ scroll--;
+ print_item(menu, items[scroll], 0, TRUE);
+#endif
+ wnoutrefresh(menu);
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, item_x, cur_x, cur_y);
+ print_position(dialog, box_x+menu_width, box_y+menu_height, scroll+choice, item_no);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */
+ wrefresh(dialog);
+ }
+ continue; /* wait for another key press */
+ }
+ else
+ i = choice - 1;
+ }
+ else if (key == KEY_DOWN || key == '+') {
+ if (choice == max_choice - 1) {
+ if (scroll+choice < item_no-1) {
+#ifdef BROKEN_WSCRL
+ /* wscrl() in ncurses 1.8.1 seems to be broken, causing a segmentation
+ violation when scrolling windows of height = 4, so scrolling is not
+ used for now */
+ scroll++;
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ /* Reprint menu to scroll up */
+ for (i = 0; i < max_choice; i++)
+ print_item(menu, items[(scroll+i)], i, i == choice);
+
+#else
+
+ /* Scroll menu up */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ if (menu_height > 1) {
+ /* De-highlight current last item before scrolling up */
+ print_item(menu, items[(scroll+max_choice-1)], max_choice-1, FALSE);
+ scrollok(menu, TRUE);
+ scroll(menu);
+ scrollok(menu, FALSE);
+ }
+ scroll++;
+ print_item(menu, items[(scroll+max_choice-1)], max_choice-1, TRUE);
+#endif
+ wnoutrefresh(menu);
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, item_x, cur_x, cur_y);
+ print_position(dialog, box_x+menu_width, box_y+menu_height, scroll+choice, item_no);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */
+ wrefresh(dialog);
+ }
+ continue; /* wait for another key press */
+ }
+ else
+ i = choice + 1;
+ }
+
+ if (i != choice) {
+ /* De-highlight current item */
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ print_item(menu, items[(scroll+choice)], choice, FALSE);
+
+ /* Highlight new item */
+ choice = i;
+ print_item(menu, items[(scroll+choice)], choice, TRUE);
+ wnoutrefresh(menu);
+ print_position(dialog, box_x+menu_width, box_y+menu_height, scroll+choice, item_no);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */
+ wrefresh(dialog);
+ }
+ continue; /* wait for another key press */
+ }
+
+ /* save info about menu item position */
+ if (ch)
+ *ch = choice;
+ if (sc)
+ *sc = scroll;
+
+ switch (key) {
+ case KEY_PPAGE:
+ case 'B' :
+ case 'b' :
+ if (scroll > menu_height) { /* can we go up? */
+ scroll -= (menu_height);
+ } else {
+ scroll = 0;
+ }
+ redraw_menu = TRUE;
+ break;
+ case KEY_NPAGE:
+ case 'F' :
+ case 'f' :
+ if (scroll + menu_height >= item_no-1 - menu_height) { /* can we go down a full page? */
+ scroll = item_no - menu_height;
+ if (scroll < 0) scroll = 0;
+ } else {
+ scroll += menu_height;
+ }
+ redraw_menu = TRUE;
+ break;
+ case KEY_HOME:
+ case 'g' :
+ scroll = 0;
+ choice = 0;
+ redraw_menu = TRUE;
+ break;
+ case KEY_END:
+ case 'G' :
+ scroll = item_no - menu_height;
+ if (scroll < 0) scroll = 0;
+ choice = max_choice - 1;
+ redraw_menu = TRUE;
+ break;
+ case 'O':
+ case 'o':
+ delwin(dialog);
+ *result = scroll+choice;
+ return 0;
+ case 'C':
+ case 'c':
+ delwin(dialog);
+ return 1;
+ case KEY_BTAB:
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ if (!button) {
+ button = 1; /* Indicates "Cancel" button is selected */
+ print_button(dialog, " OK ", y, x, FALSE);
+ print_button(dialog, "Cancel", y, x+14, TRUE);
+ }
+ else {
+ button = 0; /* Indicates "OK" button is selected */
+ print_button(dialog, "Cancel", y, x+14, FALSE);
+ print_button(dialog, " OK ", y, x, TRUE);
+ }
+ wrefresh(dialog);
+ break;
+ case ' ':
+ case '\r':
+ case '\n':
+ delwin(dialog);
+ if (!button)
+ *result = scroll+choice;
+ return button;
+ case ESC:
+ break;
+ case KEY_F(1):
+ case '?':
+ display_helpfile();
+ break;
+ }
+ if (redraw_menu) {
+ for (i = 0; i < max_choice; i++) {
+ print_item(menu, items[(scroll+i)],
+ i, i == choice);
+ }
+ wnoutrefresh(menu);
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+ print_arrows(dialog, scroll, menu_height, item_no, box_x, box_y, item_x, cur_x, cur_y);
+ print_position(dialog, box_x+menu_width, box_y+menu_height, scroll+choice, item_no);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor to previous position */
+ wrefresh(dialog);
+ redraw_menu = FALSE;
+ }
+ }
+
+ delwin(dialog);
+ return -1; /* ESC pressed */
+}
+/* End of dialog_treemenu() */
+
+
+/*
+ * Print menu item
+ */
+static void print_item(WINDOW *win, struct leaf item, int choice, int selected)
+{
+ int i, j = menu_width - 2;
+ char *branches = item.branches;
+
+ /* Clear 'residue' of last item */
+ wattrset(win, menubox_attr);
+ wmove(win, choice, 0);
+ for (i = 0; i < menu_width; i++)
+ waddch(win, ' ');
+ wmove(win, choice, item_x);
+
+ while(*branches && j)
+ {
+ switch (*branches++) {
+ case ' ' : waddch(win, ' ');
+ break;
+ case '|' : waddch(win, ACS_VLINE);
+ }
+
+ j--;
+ i = 3;
+ while(i-- && j)
+ {
+ waddch(win, ' ');
+ j--;
+ }
+ }
+
+ if (j)
+ {
+ switch (item.slip) {
+ case '+' : waddch(win, ACS_LTEE);
+ break;
+ case '`' : waddch(win, ACS_LLCORNER);
+ }
+ j--;
+ }
+
+ i = 3;
+ while(i-- && j)
+ {
+ waddch(win, ACS_HLINE);
+ j--;
+ }
+
+ wattrset(win, selected ? item_selected_attr : item_attr);
+ if (j)
+ waddnstr(win, item.name, j);
+}
+/* End of print_item() */
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW *win, int x, int y,
+ int cur_pos, int size)
+{
+ int percent;
+
+ wattrset(win, position_indicator_attr);
+ percent = cur_pos == size - 1 ? 100 : (cur_pos * 100)/(size - 1);
+ wmove(win, y + 1, x - 6);
+ wprintw(win, "(%3d%%)", percent);
+}
+/* End of print_position() */
+
+/*
+ * Display a tree menu from file
+ *
+ * filename - file with like find(1) output
+ * FS - fields separator
+ * title - title of dialog box
+ * prompt - prompt text into dialog box
+ * height - height of dialog box
+ * width - width of dialog box
+ * menu_height - height of menu box
+ * result - pointer to char array
+ *
+ * return values:
+ * -1 - ESC pressed
+ * 0 - Ok, result set (must be freed later)
+ * 1 - Cancel
+ */
+
+int dialog_ftree(unsigned char *filename, unsigned char FS,
+ unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ unsigned char **result)
+{
+ int retcode, choice, size;
+ struct leaf *items;
+ unsigned char **names;
+
+ if (mk_ftree(filename, &names, &size, FS, &items))
+ {
+ perror("dialog_ftree");
+ end_dialog();
+ exit(-1);
+ }
+
+ if (!size)
+ {
+ fprintf(stderr, "\ndialog_ftree: file %s is empty\n", filename);
+ end_dialog();
+ exit(-1);
+ }
+
+ retcode = dialog_treemenu(title, prompt, height, width, menu_height,
+ size, items, &choice, NULL, NULL);
+
+ free_leafs(items, size);
+
+ if (!retcode)
+ *result = free_names(names, size, choice);
+ else
+ (void)free_names(names, size, -1);
+
+ return retcode;
+}
+/* End of dialog_ftree() */
+
+/*
+ * Display a tree menu from array
+ *
+ * names - array with like find(1) output
+ * size - size of array
+ * FS - fields separator
+ * title - title of dialog box
+ * prompt - prompt text into dialog box
+ * height - height of dialog box
+ * width - width of dialog box
+ * menu_height - height of menu box
+ * result - pointer to char array
+ *
+ * return values:
+ * -1 - ESC pressed
+ * 0 - Ok, result set
+ * 1 - Cancel
+ */
+
+int dialog_tree(unsigned char **names, int size, unsigned char FS,
+ unsigned char *title, unsigned char *prompt,
+ int height, int width, int menu_height,
+ unsigned char **result)
+{
+ int retcode, choice;
+ struct leaf *items;
+ struct saved_tree *st;
+ static struct queue *q_saved_tree = NULL;
+
+ if (!size)
+ {
+ fprintf(stderr, "\ndialog_tree: source array is empty\n");
+ end_dialog();
+ exit(-1);
+ }
+
+ if (mk_tree(names, size, FS, &items))
+ {
+ perror("dialog_tree");
+ end_dialog();
+ exit(-1);
+ }
+
+/* is tree saved ? */
+ if (!(st = search_saved_tree(q_saved_tree, names,
+ size, FS,
+ height, width, menu_height))) {
+ if (!q_saved_tree) {
+ if (!(q_saved_tree =
+ calloc(sizeof (struct queue), 1))) {
+ perror("dialog_tree");
+ end_dialog();
+ exit(-1);
+ }
+ }
+
+ if (!(st = calloc(sizeof (struct saved_tree), 1))) {
+ perror("dialog_tree");
+ end_dialog();
+ exit(-1);
+ }
+
+ st->names = names;
+ st->size = size;
+ st->FS = FS;
+ st->height = height;
+ st->width = width;
+ st->menu_height = menu_height;
+
+ if (!p2_queue(q_saved_tree, st)) {
+ perror("dialog_tree");
+ end_dialog();
+ exit(-1);
+ }
+ }
+
+ retcode = dialog_treemenu(title, prompt, height, width, menu_height,
+ size, items, &choice,
+ &(st->ch), &(st->sc));
+
+ free_leafs(items, size);
+
+ if (!retcode)
+ *result = names[choice];
+
+ return retcode;
+}
+/* End of dialog_tree() */
+
+/* utils for ftree */
+
+/* init struct queue by zeros */
+static void
+init_queue(struct queue *queue)
+{
+ bzero((void *)queue, sizeof(struct queue));
+}
+
+/* add pointer to queue */
+/* return - pointer or NULL if error */
+static void *
+p2_queue(struct queue *queue, void *pointer)
+{
+ if (!queue)
+ return NULL;
+
+ if (!queue->first)
+ {
+ if (!(queue->first = queue->last =
+ calloc(1, sizeof(struct m_queue))))
+ return NULL;
+
+ }
+ else
+ {
+ if (!(queue->last->next =
+ calloc(1, sizeof(struct m_queue))))
+ return NULL;
+
+ queue->last = queue->last->next;
+ }
+
+ queue->size++;
+ return queue->last->pointer = pointer;
+}
+
+/* get first from queue */
+/* return - pointer or NULL if queue is empty */
+static void *
+first_queue(struct queue *queue)
+{
+ void *retval;
+ struct m_queue *new_first;
+
+ if (!queue ||
+ !queue->first ||
+ !queue->size)
+ return NULL;
+
+ retval = queue->first->pointer;
+ new_first = queue->first->next;
+ free(queue->first);
+ queue->first = new_first;
+ queue->size--;
+
+ return retval;
+
+}
+
+/* make zero terminated array from queue */
+/* return - pointer to array or NULL if error */
+static void **
+q2arr(struct queue *queue, int depth)
+{
+ void **mono, **end;
+
+ if (!queue ||
+ !queue->first ||
+ !queue->size)
+ return NULL;
+
+ /* memory allocation for array */
+ if (!(mono = end = malloc(depth * sizeof(void *) + 1)))
+ return NULL;
+
+ while(depth--)
+ {
+ if (!(*end++ = first_queue(queue)))
+ break;
+ }
+
+ *end = NULL;
+
+ return mono;
+
+}
+
+/*
+ * smart_tree (for like find(1) with -d flag output compliance)
+ *
+ * return values:
+ * NULL - malloc error
+ * not NULL - ok
+ *
+ */
+static
+unsigned char *
+smart_tree(struct queue *queue,
+ unsigned char FS,
+ unsigned char *current,
+ unsigned char *prev) {
+ unsigned char *pcurrent = current, *pprev = prev, *toqueue;
+ register char break_flag = 0;
+
+ while(*pcurrent && *pprev) {
+ if (*pcurrent == *pprev) {
+ pcurrent++;
+ pprev++;
+ }
+ else {
+ break_flag = 1;
+ break;
+ }
+ }
+
+ if (!*pprev || break_flag) {
+ if (*pcurrent == FS) {
+ pcurrent++;
+
+ if ((!*prev) && (*pcurrent)) {
+ unsigned char tchar = *pcurrent;
+
+ *pcurrent = '\0';
+ if (!(toqueue = strdup(current))) {
+ *pcurrent = tchar;
+ return NULL;
+ }
+ if (!p2_queue(queue, toqueue)) {
+ *pcurrent = tchar;
+ return NULL;
+ }
+ *pcurrent = tchar;
+ }
+ }
+
+ while(*pcurrent) {
+ if (*pcurrent == FS) {
+ *pcurrent = '\0';
+ if (!(toqueue = strdup(current))) {
+ *pcurrent = FS;
+ return NULL;
+ }
+ if (!p2_queue(queue, toqueue)) {
+ *pcurrent = FS;
+ return NULL;
+ }
+ *pcurrent = FS;
+ }
+ pcurrent++;
+ }
+ if (!p2_queue(queue, current))
+ return NULL;
+ }
+ return current;
+}
+
+/* end of utils for ftree */
+
+/* utils for make tree */
+
+/* if error - return -1 */
+static
+int
+mk_slip(struct leaf array[], int arr_size, int number, int shift)
+{
+ int t_number;
+ int t_shift;
+
+ if (number > arr_size - 1)
+ return number - 1;
+
+ t_shift = shift;
+
+ if (!(array[number].branches = calloc(1, t_shift + 1)))
+ return -1;
+
+ (void)memset(array[number].branches, ' ', t_shift);
+
+ t_number = number;
+
+ while (array[number].shift < array[t_number + 1].shift)
+ {
+ t_number = mk_slip(array, arr_size, t_number + 1, t_shift + 1);
+ if (t_number < 0)
+ return -1;
+ if (t_number == arr_size - 1)
+ break;
+ }
+
+ if (array[number].shift == array[t_number + 1].shift)
+ array[number].slip = '+';
+
+ if ((array[number].shift > array[t_number + 1].shift) ||
+ t_number == arr_size - 1)
+ array[number].slip = '`';
+
+ return t_number;
+
+} /* mk_slip() */
+
+/* make tree from file
+ *
+ * filename - name of file with like find(1) output
+ * p_names - pointer to array of strings
+ * p_size - pointer to size of array
+ * FS - fields separator
+ * p_array - pointer to array of leafs
+ *
+ * return values:
+ * 0 - ok and names by p_names, size by p_size, array by p_array set
+ * -1 - memory allocation error (errno set)
+ */
+
+static
+int
+mk_ftree(char *filename,
+ unsigned char ***p_names, int *p_size, unsigned char FS,
+ struct leaf **p_array)
+{
+ int NR; /* number of input records */
+ struct queue queue;
+ unsigned char *string, *sstring = "";
+ unsigned char **names;
+
+ FILE *input_file;
+
+ if (!(input_file = fopen(filename, "r")))
+ return -1;
+
+ init_queue(&queue);
+
+ if (!(string = malloc(BUFSIZ)))
+ return -1;
+
+ /* read input file into queue */
+ while(fgets(string, BUFSIZ, input_file))
+ {
+ if (strchr(string, '\n'))
+ *strchr(string, '\n') = '\0';
+
+ if (!(string = realloc(string, strlen(string) + 1)))
+ return -1;
+
+ if (!smart_tree(&queue, FS, string, sstring))
+ return -1;
+ sstring = string;
+
+ if (!(string = malloc(BUFSIZ)))
+ return -1;
+ } /* read input file into queue */
+
+ if (fclose(input_file) == EOF)
+ return -1;
+
+ if (!(NR = queue.size))
+ {
+ *p_size = 0;
+ return 0;
+ }
+
+ /* make array from queue */
+ if (!(names = (unsigned char **)q2arr(&queue, NR)))
+ return -1;
+
+ *p_names = names;
+ *p_size = NR;
+
+ /* make tree from array */
+ return mk_tree(names, NR, FS, p_array);
+
+} /* mk_ftree */
+
+/* make tree from array
+ *
+ * names - array of strings
+ * size - size of array
+ * FS - fields separator
+ * p_array - pointer to array of leafs
+ *
+ * return values:
+ * 0 - ok and array by p_array set
+ * -1 - memory allocation error (errno set)
+ */
+
+static
+int
+mk_tree(unsigned char **names, int size, unsigned char FS,
+ struct leaf **p_array)
+{
+ int i;
+ struct leaf *array;
+
+ /* make array of leafs */
+ if (!(array = calloc(size, sizeof(struct leaf))))
+ return -1;
+
+ /* init leafs */
+ for (i = 0; i < size; i++)
+ {
+ unsigned char *in_string, *name;
+ int shift = 0;
+
+ in_string = name = names[i];
+ while(*in_string)
+ {
+ if (*in_string == FS) {
+ if (!i && !*(in_string + 1))
+ name = in_string;
+ else
+ {
+ shift++;
+ name = in_string + 1;
+ }
+ }
+ in_string++;
+ }
+ array[i].name = name;
+ array[i].shift = shift;
+ array[i].slip = '\0';
+ array[i].branches = NULL;
+ } /* init leafs */
+
+ /* make slips */
+ for (i = 0;i < size; i++)
+ {
+ i = mk_slip(array, size, i, 0);
+ if (i < 0)
+ return -1;
+ } /* make slips */
+
+ /* make branches */
+ for (i = 1;i < size; i++)
+ {
+ unsigned char *src = array[i - 1].branches;
+ unsigned char *dst = array[i].branches;
+
+ while(*src && *dst)
+ *dst++ = *src++;
+
+ if (*dst)
+ switch (array[i - 1].slip) {
+ case '+' : *dst = '|';
+ break;
+ case '`' : *dst = ' ';
+ }
+ } /* make branches */
+
+ *p_array = array;
+ return 0;
+
+} /* mk_tree() */
+
+/* free memory from tree (leafs)
+ *
+ * return values:
+ * nothing
+ */
+
+static
+void
+free_leafs(struct leaf *array, int size)
+{
+ struct leaf *p_array = array;
+
+ while (size--)
+ free(array++->branches);
+
+ free(p_array);
+} /* free_leafs() */
+
+/* free memory from source data for tree (names)
+ *
+ * return values:
+ * if 0 <= choice <= size - pointer to name from names,
+ * and memory for name not released (must be freed later)
+ * else - NULL (recomended choice -1 for it)
+ */
+
+static
+unsigned char *
+free_names(unsigned char **names, int size, int choice)
+{
+ unsigned char *retval = NULL;
+ unsigned char **p_names = names;
+
+ while (size--)
+ {
+ if (!choice--)
+ retval = *names++;
+ else
+ free(*names++);
+ }
+ free(p_names);
+ return retval;
+} /* free_names() */
+
+/* end of utils for make tree */
+
+/* static utils for saved_tree */
+
+/* search saved tree within queue */
+/* return - struct *saved_tree or NULL if not found */
+static
+struct saved_tree *
+search_saved_tree(struct queue *queue, unsigned char **names, int size,
+ unsigned char FS,
+ int height, int width,
+ int menu_height)
+{
+ struct m_queue *member;
+ struct saved_tree *retval;
+
+ if (!queue || !names || !FS ||
+ !height || !width || !menu_height)
+ return NULL;
+
+ if (!(member = queue->first))
+ return NULL;
+
+ while (member->next) {
+ retval = member->pointer;
+ if ((names == retval->names) &&
+ (size == retval->size) &&
+ (FS == retval->FS) &&
+ (height == retval->height) &&
+ (width == retval->width) &&
+ (menu_height == retval->menu_height))
+ return retval;
+ member = member->next;
+ }
+ retval = member->pointer;
+ if ((names == retval->names) &&
+ (size == retval->size) &&
+ (FS == retval->FS) &&
+ (height == retval->height) &&
+ (width == retval->width) &&
+ (menu_height == retval->menu_height))
+ return retval;
+ return NULL;
+}
+
+/* end of static utils for saved_tree */
diff --git a/gnu/lib/libodialog/ui_objects.c b/gnu/lib/libodialog/ui_objects.c
new file mode 100644
index 0000000..dde1513
--- /dev/null
+++ b/gnu/lib/libodialog/ui_objects.c
@@ -0,0 +1,829 @@
+/*
+ * Program: objects.c
+ * Author: Marc van Kempen
+ * Desc: Implementation of UI-objects:
+ * - String input fields
+ * - List selection
+ * - Buttons
+ *
+ * Copyright (c) 1995, Marc van Kempen
+ *
+ * All rights reserved.
+ *
+ * This software may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ *
+ */
+
+#include <stdlib.h>
+#include <sys/param.h>
+#include <ncurses.h>
+#include <dialog.h>
+#include "dialog.priv.h"
+#include "ui_objects.h"
+
+#define ESC 27
+
+/***********************************************************************
+ *
+ * Obj routines
+ *
+ ***********************************************************************/
+
+void
+AddObj(ComposeObj **Obj, int objtype, void *obj)
+/*
+ * Desc: Add the object <obj> to the list of objects <Obj>
+ */
+{
+ if (*Obj == NULL) {
+ /* Create the root object */
+ *Obj = (ComposeObj *) malloc( sizeof(ComposeObj) );
+ if (!Obj) {
+ printf("AddObj: Error malloc'ing ComposeObj\n");
+ exit(-1);
+ }
+ (*Obj)->objtype = objtype;
+ (*Obj)->obj = obj;
+ (*Obj)->next = NULL;
+ (*Obj)->prev = NULL;
+ } else {
+ ComposeObj *o = *Obj;
+
+ /* create the next object */
+ while (o->next) o = (ComposeObj *) o->next;
+ o->next = (struct ComposeObj *) malloc( sizeof(ComposeObj) );
+ if (!o->next) {
+ printf("AddObj: Error malloc'ing o->next\n");
+ exit(-1);
+ }
+ o->next->objtype = objtype;
+ o->next->obj = obj;
+ o->next->next = NULL;
+ o->next->prev = o;
+ }
+
+ return;
+} /* AddObj() */
+
+void
+FreeObj(ComposeObj *Obj)
+/*
+ * Desc: free the memory occupied by *Obj
+ */
+{
+ ComposeObj *o = Obj;
+
+ o = Obj;
+ while (o) {
+ o = Obj->next;
+ free(Obj);
+ Obj = o;
+ }
+
+ return;
+} /* FreeObj() */
+
+
+int
+ReadObj(ComposeObj *Obj)
+/*
+ * Desc: navigate through the different objects calling their
+ * respective navigation routines as necessary
+ * Pre: Obj != NULL
+ */
+{
+ ComposeObj *o;
+ ComposeObj *last; /* the last object in the list */
+ int ret; /* the return value from the selection routine */
+
+ /* find the last object in the list */
+ last = Obj;
+ while (last->next) last = last->next;
+
+ ret = 0;
+ o = Obj;
+ while ((ret != SEL_BUTTON) && (ret != SEL_ESC)) {
+ switch(o->objtype) {
+ case STRINGOBJ:
+ ret = SelectStringObj((StringObj *) o->obj);
+ break;
+ case LISTOBJ:
+ ret = SelectListObj((ListObj *) o->obj);
+ break;
+ case BUTTONOBJ:
+ ret = SelectButtonObj((ButtonObj *) o->obj);
+ break;
+ }
+ switch(ret) {
+ case KEY_DOWN:
+ case SEL_CR:
+ case SEL_TAB: /* move to the next object in the list */
+ if (o->next != NULL) {
+ o = o->next; /* next object */
+ } else {
+ o = Obj; /* beginning of the list */
+ }
+ break;
+
+ case KEY_UP:
+ case SEL_BACKTAB: /* move to the previous object in the list */
+ if (o->prev != NULL) {
+ o = o->prev; /* previous object */
+ } else {
+ o = last; /* end of the list */
+ }
+ break;
+
+ case KEY_F(1): /* display help_file */
+ case '?':
+ display_helpfile();
+ break;
+ }
+ }
+
+ return(ret);
+
+} /* ReadObj() */
+
+
+int
+PollObj(ComposeObj **Obj)
+{
+ ComposeObj *last; /* the last object in the list */
+ ComposeObj *first; /* the first object in the list */
+ int ret; /* the return value from the selection routine */
+
+ /* find the last object in the list */
+ last = *Obj;
+ while (last->next) last = last->next;
+
+ /* find the first object in the list */
+ first = *Obj;
+ while (first->prev) first = first->prev;
+
+ ret = 0;
+ switch((*Obj)->objtype) {
+ case STRINGOBJ:
+ ret = SelectStringObj((StringObj *) (*Obj)->obj);
+ break;
+ case LISTOBJ:
+ ret = SelectListObj((ListObj *) (*Obj)->obj);
+ break;
+ case BUTTONOBJ:
+ ret = SelectButtonObj((ButtonObj *) (*Obj)->obj);
+ break;
+ }
+ switch(ret) {
+ case KEY_DOWN:
+ case SEL_CR:
+ case SEL_TAB: /* move to the next object in the list */
+ if ((*Obj)->next != NULL) {
+ *Obj = (*Obj)->next; /* next object */
+ } else {
+ *Obj = first; /* beginning of the list */
+ }
+ break;
+
+ case KEY_UP:
+ case SEL_BACKTAB: /* move to the previous object in the list */
+ if ((*Obj)->prev != NULL) {
+ *Obj = (*Obj)->prev; /* previous object */
+ } else {
+ *Obj = last; /* end of the list */
+ }
+ break;
+ }
+
+ return(ret);
+
+} /* PollObj() */
+
+
+void
+DelObj(ComposeObj *Obj)
+/*
+ * Desc: Free all objects
+ */
+{
+ ComposeObj *o;
+
+ o = Obj;
+ while (Obj != NULL) {
+ switch(Obj->objtype) {
+ case STRINGOBJ:
+ DelStringObj((StringObj *) Obj->obj);
+ break;
+ case LISTOBJ:
+ DelListObj((ListObj *) Obj->obj);
+ break;
+ case BUTTONOBJ:
+ DelButtonObj((ButtonObj *) Obj->obj);
+ break;
+ }
+ Obj = Obj->next;
+ }
+
+ FreeObj(o);
+} /* DelObj() */
+
+/***********************************************************************
+ *
+ * StringObj routines
+ *
+ ***********************************************************************/
+
+static void
+outstr(WINDOW *win, char *str, int attrs)
+{
+ if (attrs & DITEM_NO_ECHO) {
+ char *cpy;
+ int n = strlen(str);
+
+ cpy = alloca(n + 1);
+ memset(cpy, '*', n);
+ cpy[n] = '\0';
+ waddstr(win, cpy);
+ }
+ else
+ waddstr(win, str);
+}
+
+void
+RefreshStringObj(StringObj *so)
+/*
+ * Desc: redraw the object
+ */
+{
+ char tmp[512];
+
+ wmove(so->win, so->y, so->x+1);
+ wattrset(so->win, dialog_attr);
+ waddstr(so->win, so->title);
+
+ draw_box(so->win, so->y+1, so->x, 3, so->w, dialog_attr, border_attr);
+ wattrset(so->win, item_attr);
+ wmove(so->win, so->y+2, so->x+1);
+ if (strlen(so->s) > so->w-2) {
+ strncpy(tmp, (char *) so->s + strlen(so->s) - so->w + 2, so->w - 1);
+ outstr(so->win, tmp, so->attr_mask);
+ } else {
+ outstr(so->win, so->s, so->attr_mask);
+ }
+
+ return;
+} /* RefreshStringObj() */
+
+StringObj *
+NewStringObj(WINDOW *win, char *title, char *s, int y, int x, int w, int len)
+/*
+ * Desc: Initialize a new stringobj and return a pointer to it.
+ * Draw the object on the screen at the specified coordinates
+ */
+{
+ StringObj *so;
+
+ /* Initialize a new object */
+ so = (StringObj *) malloc( sizeof(StringObj) );
+ if (!so) {
+ printf("NewStringObj: Error malloc'ing StringObj\n");
+ exit(-1);
+ }
+ so->title = (char *) malloc( strlen(title) + 1);
+ if (!so->title) {
+ printf("NewStringObj: Error malloc'ing so->title\n");
+ exit(-1);
+ }
+ strcpy(so->title, title);
+ so->s = s;
+ strcpy(so->s, s);
+ so->x = x;
+ so->y = y;
+ so->w = w;
+ so->len = len;
+ so->win = win;
+ so->attr_mask = DialogInputAttrs; /* Grossly use a global to avoid changing API */
+
+ /* Draw it on the screen */
+ RefreshStringObj(so);
+
+ return(so);
+} /* NewStringObj() */
+
+int
+SelectStringObj(StringObj *so)
+/*
+ * Desc: get input using the info in <so>
+ */
+{
+ int key;
+ char tmp[so->len+1];
+
+ strcpy(tmp, so->s);
+ key = line_edit(so->win, so->y+2, so->x+1,
+ so->len, so->w-2, inputbox_attr, TRUE, tmp, so->attr_mask);
+ if ((key == '\n') || (key == '\r') || (key == '\t') || key == (KEY_BTAB) ) {
+ strcpy(so->s, tmp);
+ }
+ RefreshStringObj(so);
+ if (key == ESC) {
+ return(SEL_ESC);
+ }
+ if (key == '\t') {
+ return(SEL_TAB);
+ }
+ if ( (key == KEY_BTAB) || (key == KEY_F(2)) ) {
+ return(SEL_BACKTAB);
+ }
+ if ((key == '\n') || (key == '\r')) {
+ return(SEL_CR);
+ }
+ return(key);
+} /* SelectStringObj() */
+
+
+void
+DelStringObj(StringObj *so)
+/*
+ * Desc: Free the space occupied by <so>
+ */
+{
+ free(so->title);
+ free(so);
+
+ return;
+}
+
+/***********************************************************************
+ *
+ * ListObj routines
+ *
+ ***********************************************************************/
+
+void
+DrawNames(ListObj *lo)
+/*
+ * Desc: Just refresh the names, not the surrounding box and title
+ */
+{
+ int i, j, h, x, y;
+ char tmp[MAXPATHLEN];
+
+ x = lo->x + 1;
+ y = lo->y + 2;
+ h = lo->h - 2;
+ for (i=lo->scroll; i<lo->n && i<lo->scroll+h; i++) {
+ wmove(lo->win, y+i-lo->scroll, x);
+ if (lo->seld[i]) {
+ wattrset(lo->win, A_BOLD);
+ } else {
+ wattrset(lo->win, item_attr);
+ }
+ if (strlen(lo->name[i]) > lo->w-2) {
+ strncpy(tmp, lo->name[i], lo->w-2);
+ tmp[lo->w - 2] = 0;
+ waddstr(lo->win, tmp);
+ } else {
+ waddstr(lo->win, lo->name[i]);
+ for (j=strlen(lo->name[i]); j<lo->w-2; j++) waddstr(lo->win, " ");
+ }
+ }
+ wattrset(lo->win, item_attr);
+ while (i<lo->scroll+h) {
+ wmove(lo->win, y+i-lo->scroll, x);
+ for (j=0; j<lo->w-2; j++) waddstr(lo->win, " ");
+ i++;
+ }
+
+ return;
+} /* DrawNames() */
+
+void
+RefreshListObj(ListObj *lo)
+/*
+ * Desc: redraw the list object
+ */
+{
+ char perc[7];
+
+ /* setup the box */
+ wmove(lo->win, lo->y, lo->x+1);
+ wattrset(lo->win, dialog_attr);
+ waddstr(lo->win, lo->title);
+ draw_box(lo->win, lo->y+1, lo->x, lo->h, lo->w, dialog_attr, border_attr);
+
+ /* draw the names */
+ DrawNames(lo);
+
+ /* Draw % indication */
+ sprintf(perc, "(%3d%%)", MIN(100, (int) (100 * (lo->sel+lo->h-2) / MAX(1, lo->n))));
+ wmove(lo->win, lo->y + lo->h, lo->x + lo->w - 8);
+ wattrset(lo->win, dialog_attr);
+ waddstr(lo->win, perc);
+
+
+ return;
+} /* RefreshListObj() */
+
+ListObj *
+NewListObj(WINDOW *win, char *title, char **list, char *listelt, int y, int x,
+ int h, int w, int n)
+/*
+ * Desc: create a listobj, draw it on the screen and return a pointer to it.
+ */
+{
+ ListObj *lo;
+ int i;
+
+ /* Initialize a new object */
+ lo = (ListObj *) malloc( sizeof(ListObj) );
+ if (!lo) {
+ fprintf(stderr, "NewListObj: Error malloc'ing ListObj\n");
+ exit(-1);
+ }
+ lo->title = (char *) malloc( strlen(title) + 1);
+ if (!lo->title) {
+ fprintf(stderr, "NewListObj: Error malloc'ing lo->title\n");
+ exit(-1);
+ }
+ strcpy(lo->title, title);
+ lo->name = list;
+ if (n>0) {
+ lo->seld = (int *) malloc( n * sizeof(int) );
+ if (!lo->seld) {
+ fprintf(stderr, "NewListObj: Error malloc'ing lo->seld\n");
+ exit(-1);
+ }
+ for (i=0; i<n; i++) {
+ lo->seld[i] = FALSE;
+ }
+ } else {
+ lo->seld = NULL;
+ }
+ lo->y = y;
+ lo->x = x;
+ lo->w = w;
+ lo->h = h;
+ lo->n = n;
+ lo->scroll = 0;
+ lo->sel = 0;
+ lo->elt = listelt;
+ lo->win = win;
+
+ /* Draw the object on the screen */
+ RefreshListObj(lo);
+
+ return(lo);
+} /* NewListObj() */
+
+void
+UpdateListObj(ListObj *lo, char **list, int n)
+/*
+ * Desc: Update the list in the listobject with the provided list
+ * Pre: lo->name "has been freed"
+ * "(A i: 0<=i<lo->n: "lo->name[i] has been freed")"
+ */
+{
+ int i;
+
+ if (lo->seld) {
+ free(lo->seld);
+ }
+
+ /* Rewrite the list in the object */
+ lo->name = list;
+ if (n>0) {
+ lo->seld = (int *) malloc( n * sizeof(int) );
+ if (!lo->seld) {
+ fprintf(stderr, "UpdateListObj: Error malloc'ing lo->seld\n");
+ exit(-1);
+ }
+ for (i=0; i<n; i++) {
+ lo->seld[i] = FALSE;
+ }
+ } else {
+ lo->seld = NULL;
+ }
+ lo->n = n;
+ lo->scroll = 0;
+ lo->sel = 0;
+
+ /* Draw the object on the screen */
+ RefreshListObj(lo);
+
+ return;
+} /* UpdateListObj() */
+
+int
+SelectListObj(ListObj *lo)
+/*
+ * Desc: get a listname (or listnames), TAB to move on, or ESC ESC to exit
+ * Pre: lo->n >= 1
+ */
+{
+ int key, sel_x, sel_y, quit;
+ char tmp[MAXPATHLEN];
+ char perc[4];
+
+ sel_x = lo->x+1;
+ sel_y = lo->y + 2 + lo->sel - lo->scroll;
+
+ if (lo->n == 0) return(SEL_TAB);
+
+ keypad(lo->win, TRUE);
+
+ /* Draw current selection in inverse video */
+ wmove(lo->win, sel_y, sel_x);
+ wattrset(lo->win, item_selected_attr);
+ waddstr(lo->win, lo->name[lo->sel]);
+
+ key = wgetch(lo->win);
+ quit = FALSE;
+ while ((key != '\t') && (key != '\n') && (key != '\r')
+ && (key != ESC) && (key != KEY_F(1)) && (key != '?') && !quit) {
+ /* first draw current item in normal video */
+ wmove(lo->win, sel_y, sel_x);
+ if (lo->seld[lo->sel]) {
+ wattrset(lo->win, A_BOLD);
+ } else {
+ wattrset(lo->win, item_attr);
+ }
+ if (strlen(lo->name[lo->sel]) > lo->w - 2) {
+ strncpy(tmp, lo->name[lo->sel], lo->w - 2);
+ tmp[lo->w - 2] = 0;
+ waddstr(lo->win, tmp);
+ } else {
+ waddstr(lo->win, lo->name[lo->sel]);
+ }
+
+ switch (key) {
+ case KEY_DOWN:
+ case ctrl('n'):
+ if (sel_y < lo->y + lo->h-1) {
+ if (lo->sel < lo->n-1) {
+ sel_y++;
+ lo->sel++;
+ }
+ } else {
+ if (lo->sel < lo->n-1) {
+ lo->sel++;
+ lo->scroll++;
+ DrawNames(lo);
+ wrefresh(lo->win);
+ }
+ }
+ break;
+ case KEY_UP:
+ case ctrl('p'):
+ if (sel_y > lo->y+2) {
+ if (lo->sel > 0) {
+ sel_y--;
+ lo->sel--;
+ }
+ } else {
+ if (lo->sel > 0) {
+ lo->sel--;
+ lo->scroll--;
+ DrawNames(lo);
+ wrefresh(lo->win);
+ }
+ }
+ break;
+ case KEY_HOME:
+ case ctrl('a'):
+ lo->sel = 0;
+ lo->scroll = 0;
+ sel_y = lo->y + 2;
+ DrawNames(lo);
+ wrefresh(lo->win);
+ break;
+ case KEY_END:
+ case ctrl('e'):
+ if (lo->n < lo->h - 3) {
+ lo->sel = lo->n-1;
+ lo->scroll = 0;
+ sel_y = lo->y + 2 + lo->sel - lo->scroll;
+ } else {
+ /* more than one page of list */
+ lo->sel = lo->n-1;
+ lo->scroll = lo->n-1 - (lo->h-3);
+ sel_y = lo->y + 2 + lo->sel - lo->scroll;
+ DrawNames(lo);
+ wrefresh(lo->win);
+ }
+ break;
+ case KEY_NPAGE:
+ case ctrl('f'):
+ lo->sel += lo->h - 2;
+ if (lo->sel >= lo->n) lo->sel = lo->n - 1;
+ lo->scroll += lo->h - 2;
+ if (lo->scroll >= lo->n - 1) lo->scroll = lo->n - 1;
+ if (lo->scroll < 0) lo->scroll = 0;
+ sel_y = lo->y + 2 + lo->sel - lo->scroll;
+ DrawNames(lo);
+ wrefresh(lo->win);
+ break;
+ case KEY_PPAGE:
+ case ctrl('b'):
+ lo->sel -= lo->h - 2;
+ if (lo->sel < 0) lo->sel = 0;
+ lo->scroll -= lo->h - 2;
+ if (lo->scroll < 0) lo->scroll = 0;
+ sel_y = lo->y + 2 + lo->sel - lo->scroll;
+ DrawNames(lo);
+ wrefresh(lo->win);
+ break;
+ default:
+ quit = TRUE;
+ break;
+ }
+ /* Draw % indication */
+ sprintf(perc, "(%3d%%)", MIN(100, (int)
+ (100 * (lo->sel+lo->h - 2) / MAX(1, lo->n))));
+ wmove(lo->win, lo->y + lo->h, lo->x + lo->w - 8);
+ wattrset(lo->win, dialog_attr);
+ waddstr(lo->win, perc);
+
+ /* draw current item in inverse */
+ wmove(lo->win, sel_y, sel_x);
+ wattrset(lo->win, item_selected_attr);
+ if (strlen(lo->name[lo->sel]) > lo->w - 2) {
+ /* when printing in inverse video show the last characters in the */
+ /* name that will fit in the window */
+ strncpy(tmp,
+ lo->name[lo->sel] + strlen(lo->name[lo->sel]) - (lo->w - 2),
+ lo->w - 2);
+ tmp[lo->w - 2] = 0;
+ waddstr(lo->win, tmp);
+ } else {
+ waddstr(lo->win, lo->name[lo->sel]);
+ }
+ if (!quit) key = wgetch(lo->win);
+ }
+
+ if (key == ESC) {
+ return(SEL_ESC);
+ }
+ if (key == '\t') {
+ return(SEL_TAB);
+ }
+ if ((key == KEY_BTAB) || (key == ctrl('b'))) {
+ return(SEL_BACKTAB);
+ }
+ if ((key == '\n') || (key == '\r')) {
+ strcpy(lo->elt, lo->name[lo->sel]);
+ return(SEL_CR);
+ }
+ return(key);
+} /* SelectListObj() */
+
+void
+DelListObj(ListObj *lo)
+/*
+ * Desc: Free the space occupied by the listobject
+ */
+{
+ free(lo->title);
+ if (lo->seld != NULL) free(lo->seld);
+ free(lo);
+
+ return;
+} /* DelListObj() */
+
+void
+MarkCurrentListObj(ListObj *lo)
+/*
+ * Desc: mark the current item for the selection list
+ */
+{
+ lo->seld[lo->sel] = !(lo->seld[lo->sel]);
+ DrawNames(lo);
+
+ return;
+} /* MarkCurrentListObj() */
+
+void
+MarkAllListObj(ListObj *lo)
+/*
+ * Desc: mark all items
+ */
+{
+ int i;
+
+ for (i=0; i<lo->n; i++) {
+ lo->seld[i] = TRUE;
+ }
+ DrawNames(lo);
+
+ return;
+} /* MarkAllListObj() */
+
+void
+UnMarkAllListObj(ListObj *lo)
+/*
+ * Desc: unmark all items
+ */
+{
+ int i;
+
+ for (i=0; i<lo->n; i++) {
+ lo->seld[i] = FALSE;
+ }
+ DrawNames(lo);
+
+ return;
+} /* UnMarkAllListObj() */
+
+
+/***********************************************************************
+ *
+ * ButtonObj routines
+ *
+ ***********************************************************************/
+
+
+void
+RefreshButtonObj(ButtonObj *bo)
+/*
+ * Desc: redraw the button
+ */
+{
+ draw_box(bo->win, bo->y, bo->x, 3, bo->w, dialog_attr, border_attr);
+ print_button(bo->win, bo->title, bo->y+1, bo->x+2, FALSE);
+
+ return;
+} /* RefreshButtonObj() */
+
+ButtonObj *
+NewButtonObj(WINDOW *win, char *title, int *pushed, int y, int x)
+/*
+ * Desc: Create a new button object
+ */
+{
+ ButtonObj *bo;
+
+ bo = (ButtonObj *) malloc( sizeof(ButtonObj) );
+
+ bo->win = win;
+ bo->title = (char *) malloc( strlen(title) + 1);
+ strcpy(bo->title, title);
+ bo->x = x;
+ bo->y = y;
+ bo->w = strlen(title) + 6;
+ bo->h = 3;
+ bo->pushed = pushed;
+
+ RefreshButtonObj(bo);
+
+ return(bo);
+} /* NewButtonObj() */
+
+int
+SelectButtonObj(ButtonObj *bo)
+/*
+ * Desc: Wait for buttonpresses or TAB's to move on, or ESC ESC
+ */
+{
+ int key;
+
+ print_button(bo->win, bo->title, bo->y+1, bo->x+2, TRUE);
+ wmove(bo->win, bo->y+1, bo->x+(bo->w/2)-1);
+ key = wgetch(bo->win);
+ print_button(bo->win, bo->title, bo->y+1, bo->x+2, FALSE);
+ switch(key) {
+ case '\t':
+ return(SEL_TAB);
+ break;
+ case KEY_BTAB:
+ case ctrl('b'):
+ return(SEL_BACKTAB);
+ case '\n':
+ case '\r':
+ *(bo->pushed) = TRUE;
+ return(SEL_BUTTON);
+ break;
+ case ESC:
+ return(SEL_ESC);
+ break;
+ default:
+ return(key);
+ break;
+ }
+} /* SelectButtonObj() */
+
+void
+DelButtonObj(ButtonObj *bo)
+/*
+ * Desc: Free the space occupied by <bo>
+ */
+{
+ free(bo->title);
+ free(bo);
+
+ return;
+} /* DelButtonObj() */
diff --git a/gnu/lib/libodialog/ui_objects.h b/gnu/lib/libodialog/ui_objects.h
new file mode 100644
index 0000000..b30feb8
--- /dev/null
+++ b/gnu/lib/libodialog/ui_objects.h
@@ -0,0 +1,114 @@
+/*
+ * Author: Marc van Kempen
+ * Desc: include file for UI-objects
+ *
+ * Copyright (c) 1995, Marc van Kempen
+ *
+ * All rights reserved.
+ *
+ * This software may be used, modified, copied, distributed, and
+ * sold, in both source and binary form provided that the above
+ * copyright and these terms are retained, verbatim, as the first
+ * lines of this file. Under no circumstances is the author
+ * responsible for the proper functioning of this software, nor does
+ * the author assume any responsibility for damages incurred with
+ * its use.
+ *
+ */
+
+#include "dialog.h"
+#include <ncurses.h>
+
+/***********************************************************************
+ *
+ * Defines
+ *
+ ***********************************************************************/
+
+#define ctrl(a) ((a) - 'a' + 1)
+
+/* the Object types */
+#define STRINGOBJ 1
+#define LISTOBJ 2
+#define BUTTONOBJ 3
+
+/* the return signals from the selection routines */
+/* 1000 and higher should avoid conflicts with keys pressed */
+#define SEL_CR 1001 /* return was pressed */
+#define SEL_ESC 1002 /* ESC pressed */
+#define SEL_TAB 1003 /* TAB pressed */
+#define SEL_BACKTAB 1004 /* SHIFT-TAB pressed */
+#define SEL_BUTTON 1005 /* a button was pressed */
+
+/***********************************************************************
+ *
+ * Typedefs
+ *
+ ***********************************************************************/
+
+typedef struct {
+ WINDOW *win; /* the window it's contained in */
+ char *title; /* the prompt for the input field */
+ char *s; /* initial value of the input field */
+ int x, y, w, len; /* the (y, x) position of the upperleft */
+ /* corner and the width <w> of the display */
+ /* and length <len> of the field */
+ int attr_mask; /* special attributes */
+} StringObj;
+
+typedef struct {
+ WINDOW *win; /* the windows it's contained in */
+ char *title; /* the title of the list */
+ char **name; /* the names of the list */
+ int *seld; /* the currently selected names */
+ char *elt; /* the current element in the list list[sel] */
+ int x, y, w, h, n; /* dimensions of list and # of elements (n) */
+ int scroll, sel; /* current position in the list */
+} ListObj;
+
+typedef struct {
+ WINDOW *win; /* the window it's contained in */
+ char *title; /* title for the button */
+ int x, y, w, h; /* its dimensions */
+ int *pushed; /* boolean that determines wether button was pushed */
+} ButtonObj;
+
+typedef struct ComposeObj {
+ int objtype;
+ void *obj;
+ struct ComposeObj *next, *prev;
+} ComposeObj;
+
+/**********************************************************************
+ *
+ * Prototypes
+ *
+ **********************************************************************/
+
+void RefreshStringObj(StringObj *so);
+StringObj *NewStringObj(WINDOW *win, char *title, char *s,
+ int y, int x, int w, int len);
+int SelectStringObj(StringObj *so);
+void DelStringObj(StringObj *so);
+
+void RefreshListObj(ListObj *lo);
+ListObj *NewListObj(WINDOW *win, char *title, char **list,
+ char *listelt, int y, int x, int h, int w, int n);
+void UpdateListObj(ListObj *lo, char **list, int n);
+int SelectListObj(ListObj *lo);
+void DelListObj(ListObj *obj);
+void MarkCurrentListObj(ListObj *lo);
+void MarkAllListObj(ListObj *lo);
+void UnMarkAllListObj(ListObj *lo);
+
+void RefreshButtonObj(ButtonObj *bo);
+ButtonObj *NewButtonObj(WINDOW *win, char *title, int *pushed,
+ int y, int x);
+int SelectButtonObj(ButtonObj *bo);
+void DelButtonObj(ButtonObj *bo);
+void AddObj(ComposeObj **Obj, int objtype, void *obj);
+void FreeObj(ComposeObj *Obj);
+int ReadObj(ComposeObj *Obj);
+int PollObj(ComposeObj **Obj);
+void DelObj(ComposeObj *Obj);
+
diff --git a/gnu/lib/libodialog/yesno.c b/gnu/lib/libodialog/yesno.c
new file mode 100644
index 0000000..24eb41a
--- /dev/null
+++ b/gnu/lib/libodialog/yesno.c
@@ -0,0 +1,169 @@
+/*
+ * yesno.c -- implements the yes/no box
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <dialog.h>
+#include "dialog.priv.h"
+
+/* Actual work function */
+static int dialog_yesno_proc(unsigned char *title, unsigned char *prompt,
+ int height, int width, int yesdefault);
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int
+dialog_yesno(unsigned char *title, unsigned char *prompt, int height, int width)
+{
+ return dialog_yesno_proc(title, prompt, height, width, TRUE);
+}
+
+/*
+ * Display a dialog box with two buttons - No and Yes
+ */
+int
+dialog_noyes(unsigned char *title, unsigned char *prompt, int height, int width)
+{
+ return dialog_yesno_proc(title, prompt, height, width, FALSE);
+}
+
+static int
+dialog_yesno_proc(unsigned char *title, unsigned char *prompt, int height, int width, int yesdefault)
+{
+ int i, j, x, y, key, button;
+ WINDOW *dialog;
+ char *tmphlp;
+
+ /* disable helpline */
+ tmphlp = get_helpline();
+ use_helpline(NULL);
+
+ if (height < 0)
+ height = strheight(prompt)+4;
+ if (width < 0) {
+ i = strwidth(prompt);
+ j = ((title != NULL) ? strwidth(title) : 0);
+ width = MAX(i,j)+4;
+ }
+ width = MAX(width,23);
+
+ if (width > COLS)
+ width = COLS;
+ if (height > LINES)
+ height = LINES;
+ /* center dialog box on screen */
+ x = DialogX ? DialogX : (COLS - width)/2;
+ y = DialogY ? DialogY : (LINES - height)/2;
+
+#ifdef HAVE_NCURSES
+ if (use_shadow)
+ draw_shadow(stdscr, y, x, height, width);
+#endif
+ dialog = newwin(height, width, y, x);
+ if (dialog == NULL) {
+ endwin();
+ fprintf(stderr, "\nnewwin(%d,%d,%d,%d) failed, maybe wrong dims\n", height,width,y,x);
+ exit(1);
+ }
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+ wattrset(dialog, border_attr);
+ wmove(dialog, height-3, 0);
+ waddch(dialog, ACS_LTEE);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dialog_attr);
+ waddch(dialog, ACS_RTEE);
+ wmove(dialog, height-2, 1);
+ for (i = 0; i < width-2; i++)
+ waddch(dialog, ' ');
+
+ if (title != NULL) {
+ wattrset(dialog, title_attr);
+ wmove(dialog, 0, (width - strlen(title))/2 - 1);
+ waddch(dialog, ' ');
+ waddstr(dialog, title);
+ waddch(dialog, ' ');
+ }
+ wattrset(dialog, dialog_attr);
+ wmove(dialog, 1, 2);
+ print_autowrap(dialog, prompt, height-1, width-2, width, 1, 2, TRUE, FALSE);
+
+ display_helpline(dialog, height-1, width);
+
+ x = width/2-10;
+ y = height-2;
+
+ /* preset button 0 or 1 for YES or NO as the default */
+ key = 0;
+ button = !yesdefault;
+ while (key != ESC) {
+ print_button(dialog, " No ", y, x+13, button);
+ print_button(dialog, " Yes " , y, x, !button);
+ if (button)
+ wmove(dialog, y, x+16);
+ else
+ wmove(dialog, y, x+2);
+ wrefresh(dialog);
+
+ key = wgetch(dialog);
+ switch (key) {
+ case 'Y':
+ case 'y':
+ delwin(dialog);
+ restore_helpline(tmphlp);
+ return 0;
+ case 'N':
+ case 'n':
+ delwin(dialog);
+ restore_helpline(tmphlp);
+ return 1;
+ case KEY_BTAB:
+ case TAB:
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ button = !button;
+ /* redrawn at the loop's entry */
+ break;
+ case ' ':
+ case '\r':
+ case '\n':
+ delwin(dialog);
+ restore_helpline(tmphlp);
+ return button;
+ case ESC:
+ break;
+ case KEY_F(1):
+ case '?':
+ display_helpfile();
+ break;
+ }
+ }
+
+ delwin(dialog);
+ restore_helpline(tmphlp);
+ return -1; /* ESC pressed */
+}
+/* End of dialog_yesno() */
diff --git a/gnu/lib/libreadline/Makefile b/gnu/lib/libreadline/Makefile
new file mode 100644
index 0000000..637dcc8
--- /dev/null
+++ b/gnu/lib/libreadline/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SUBDIR = history readline
+
+.include <bsd.subdir.mk>
diff --git a/gnu/lib/libreadline/Makefile.inc b/gnu/lib/libreadline/Makefile.inc
new file mode 100644
index 0000000..992f929
--- /dev/null
+++ b/gnu/lib/libreadline/Makefile.inc
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+SHLIB_MAJOR=8
+RL_LIBRARY_VERSION=5.2
+
+SRCDIR= ${.CURDIR}/../../../../contrib/libreadline
+.PATH: ${SRCDIR} ${.CURDIR}/..
+
+LOCAL_CFLAGS= -DRL_LIBRARY_VERSION='"$(RL_LIBRARY_VERSION)"'
+CFLAGS+=-I${.CURDIR}/.. -I${SRCDIR} -DHAVE_CONFIG_H ${LOCAL_CFLAGS}
+
+HISTSRC=history.c histexpand.c histfile.c histsearch.c shell.c mbutil.c
+
+.include "../Makefile.inc"
diff --git a/gnu/lib/libreadline/config.h b/gnu/lib/libreadline/config.h
new file mode 100644
index 0000000..c13b50c
--- /dev/null
+++ b/gnu/lib/libreadline/config.h
@@ -0,0 +1,270 @@
+/* $FreeBSD$ */
+/* config.h. Generated by configure. */
+/* config.h.in. Maintained by hand. */
+
+/* Define NO_MULTIBYTE_SUPPORT to not compile in support for multibyte
+ characters, even if the OS supports them. */
+/* #undef NO_MULTIBYTE_SUPPORT */
+
+/* Define if on MINIX. */
+/* #undef _MINIX */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+#define VOID_SIGHANDLER 1
+
+/* Characteristics of the compiler. */
+/* #undef const */
+
+/* #undef size_t */
+
+/* #undef ssize_t */
+
+#define PROTOTYPES 1
+
+/* #undef __CHAR_UNSIGNED__ */
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+/* #undef STAT_MACROS_BROKEN */
+
+/* Define if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define if you have the getpwent function. */
+#define HAVE_GETPWENT 1
+
+/* Define if you have the getpwnam function. */
+#define HAVE_GETPWNAM 1
+
+/* Define if you have the getpwuid function. */
+#define HAVE_GETPWUID 1
+
+/* Define if you have the isascii function. */
+#define HAVE_ISASCII 1
+
+/* Define if you have the iswctype function. */
+#define HAVE_ISWCTYPE 1
+
+/* Define if you have the iswlower function. */
+#define HAVE_ISWLOWER 1
+
+/* Define if you have the iswupper function. */
+#define HAVE_ISWUPPER 1
+
+/* Define if you have the isxdigit function. */
+#define HAVE_ISXDIGIT 1
+
+/* Define if you have the kill function. */
+#define HAVE_KILL 1
+
+/* Define if you have the lstat function. */
+#define HAVE_LSTAT 1
+
+/* Define if you have the mbrlen function. */
+#define HAVE_MBRLEN 1
+
+/* Define if you have the mbrtowc function. */
+#define HAVE_MBRTOWC 1
+
+/* Define if you have the mbsrtowcs function. */
+#define HAVE_MBSRTOWCS 1
+
+/* Define if you have the memmove function. */
+#define HAVE_MEMMOVE 1
+
+/* Define if you have the putenv function. */
+#define HAVE_PUTENV 1
+
+/* Define if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define if you have the setenv function. */
+#define HAVE_SETENV 1
+
+/* Define if you have the setlocale function. */
+#define HAVE_SETLOCALE 1
+
+/* Define if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define if you have the strcoll function. */
+#define HAVE_STRCOLL 1
+
+/* #undef STRCOLL_BROKEN */
+
+/* Define if you have the strpbrk function. */
+#define HAVE_STRPBRK 1
+
+/* Define if you have the tcgetattr function. */
+#define HAVE_TCGETATTR 1
+
+/* Define if you have the towlower function. */
+#define HAVE_TOWLOWER 1
+
+/* Define if you have the towupper function. */
+#define HAVE_TOWUPPER 1
+
+/* Define if you have the vsnprintf function. */
+#define HAVE_VSNPRINTF 1
+
+/* Define if you have the wcrtomb function. */
+#define HAVE_WCRTOMB 1
+
+/* Define if you have the wcscoll function. */
+#define HAVE_WCSCOLL 1
+
+/* Define if you have the wctype function. */
+#define HAVE_WCTYPE 1
+
+/* Define if you have the wcwidth function. */
+#define HAVE_WCWIDTH 1
+
+#define STDC_HEADERS 1
+
+/* Define if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <langinfo.h> header file. */
+#define HAVE_LANGINFO_H 1
+
+/* Define if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <ndir.h> header file. */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define if you have the <sys/dir.h> header file. */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/file.h> header file. */
+#define HAVE_SYS_FILE_H 1
+
+/* Define if you have the <sys/ndir.h> header file. */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/pte.h> header file. */
+/* #undef HAVE_SYS_PTE_H */
+
+/* Define if you have the <sys/ptem.h> header file. */
+/* #undef HAVE_SYS_PTEM_H */
+
+/* Define if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define if you have the <sys/stream.h> header file. */
+/* #undef HAVE_SYS_STREAM_H */
+
+/* Define if you have the <termcap.h> header file. */
+#define HAVE_TERMCAP_H 1
+
+/* Define if you have the <termio.h> header file. */
+/* #undef HAVE_TERMIO_H */
+
+/* Define if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the <varargs.h> header file. */
+/* #undef HAVE_VARARGS_H */
+
+/* Define if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+#define HAVE_MBSTATE_T 1
+
+/* Define if you have wchar_t in <wctype.h>. */
+#define HAVE_WCHAR_T 1
+
+/* Define if you have wctype_t in <wctype.h>. */
+#define HAVE_WCTYPE_T 1
+
+/* Define if you have wint_t in <wctype.h>. */
+#define HAVE_WINT_T 1
+
+/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
+#define HAVE_LANGINFO_CODESET 1
+
+/* Definitions pulled in from aclocal.m4. */
+#define VOID_SIGHANDLER 1
+
+/* #undef GWINSZ_IN_SYS_IOCTL */
+
+#define STRUCT_WINSIZE_IN_SYS_IOCTL 1
+
+/* #undef STRUCT_WINSIZE_IN_TERMIOS */
+
+#define TIOCSTAT_IN_SYS_IOCTL 1
+
+#define FIONREAD_IN_SYS_IOCTL 1
+
+/* #undef SPEED_T_IN_SYS_TYPES */
+
+#define HAVE_GETPW_DECLS 1
+
+/* #undef STRUCT_DIRENT_HAS_D_INO */
+
+/* #undef STRUCT_DIRENT_HAS_D_FILENO */
+
+/* #undef HAVE_BSD_SIGNALS */
+
+#define HAVE_POSIX_SIGNALS 1
+
+/* #undef HAVE_USG_SIGHOLD */
+
+/* #undef MUST_REINSTALL_SIGHANDLERS */
+
+#define HAVE_POSIX_SIGSETJMP 1
+
+#define CTYPE_NON_ASCII 1
+
+/* modify settings or make new ones based on what autoconf tells us. */
+
+/* Ultrix botches type-ahead when switching from canonical to
+ non-canonical mode, at least through version 4.3 */
+#if !defined (HAVE_TERMIOS_H) || !defined (HAVE_TCGETATTR) || defined (ultrix)
+# define TERMIOS_MISSING
+#endif
+
+#if defined (STRCOLL_BROKEN)
+# define HAVE_STRCOLL 1
+#endif
+
+#if defined (__STDC__) && defined (HAVE_STDARG_H)
+# define PREFER_STDARG
+# define USE_VARARGS
+#else
+# if defined (HAVE_VARARGS_H)
+# define PREFER_VARARGS
+# define USE_VARARGS
+# endif
+#endif
diff --git a/gnu/lib/libreadline/history/Makefile b/gnu/lib/libreadline/history/Makefile
new file mode 100644
index 0000000..1602872
--- /dev/null
+++ b/gnu/lib/libreadline/history/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+SUBDIR= doc
+
+LIB= history
+MAN= rlhistory.3
+
+SRCS= $(HISTSRC) xmalloc.c
+
+rlhistory.3: doc/history.3
+ cp -f ${.ALLSRC} ${.TARGET}
+
+CLEANFILES+= rlhistory.3
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libreadline/history/doc/Makefile b/gnu/lib/libreadline/history/doc/Makefile
new file mode 100644
index 0000000..4b050e7
--- /dev/null
+++ b/gnu/lib/libreadline/history/doc/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+SRCDIR= ${.CURDIR}/../../../../../contrib/libreadline/doc
+
+INFO = history
+
+INFOSECTION= "Programming & development tools."
+INFOENTRY_history= "* History: (history). The GNU History library."
+
+history.info: history.texi hstech.texi hsuser.texi version.texi fdl.texi
+
+.include <bsd.info.mk>
diff --git a/gnu/lib/libreadline/readline/Makefile b/gnu/lib/libreadline/readline/Makefile
new file mode 100644
index 0000000..fab4aa2
--- /dev/null
+++ b/gnu/lib/libreadline/readline/Makefile
@@ -0,0 +1,27 @@
+# $FreeBSD$
+
+SUBDIR= doc
+
+LIB= readline
+MAN= doc/readline.3
+SHLIBDIR?= /lib
+
+TILDESRC= tilde.c
+SRCS= readline.c vi_mode.c funmap.c keymaps.c parens.c search.c \
+ rltty.c complete.c bind.c isearch.c display.c signals.c \
+ util.c kill.c undo.c macro.c input.c callback.c terminal.c \
+ text.c nls.c misc.c compat.c xmalloc.c $(HISTSRC) $(TILDESRC)
+
+INSTALLED_HEADERS= readline.h chardefs.h keymaps.h history.h tilde.h \
+ rlstdc.h rlconf.h rltypedefs.h
+
+DPADD= ${LIBTERMCAP}
+LDADD= -ltermcap
+
+INCSDIR=${INCLUDEDIR}/readline
+
+.for hdr in ${INSTALLED_HEADERS}
+INCS+= ${SRCDIR}/${hdr}
+.endfor
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libreadline/readline/doc/Makefile b/gnu/lib/libreadline/readline/doc/Makefile
new file mode 100644
index 0000000..7028971
--- /dev/null
+++ b/gnu/lib/libreadline/readline/doc/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+SRCDIR= ${.CURDIR}/../../../../../contrib/libreadline/doc
+
+INFO = readline rluserman
+
+INFOSECTION= "Programming & development tools."
+INFOENTRY_readline= "* Readline: (readline). The GNU Readline library"
+INFOENTRY_rluserman= "* Readline: (readline). The GNU readline library API"
+
+CLEANFILES += readline.texi
+
+readline.info: rlman.texi rluser.texi rltech.texi version.texi fdl.texi
+
+readline.texi: rlman.texi
+ cp -f ${SRCDIR}/rlman.texi ${.TARGET}
+
+rluserman.info: rluserman.texi version.texi rluser.texi fdl.texi
+
+.include <bsd.info.mk>
diff --git a/gnu/lib/libregex/FREEBSD-upgrade b/gnu/lib/libregex/FREEBSD-upgrade
new file mode 100644
index 0000000..d072aaf
--- /dev/null
+++ b/gnu/lib/libregex/FREEBSD-upgrade
@@ -0,0 +1,18 @@
+$FreeBSD$
+
+GNU regex (from glibc):
+
+Imported by:
+
+cvs -z 9 -d :pserver:anoncvs@sources.redhat.com:/cvs/glibc login
+# enter "anoncvs" as the password
+cvs -z 9 -d :pserver:anoncvs@sources.redhat.com:/cvs/glibc \
+ co -r fedora-glibc-2_3_4-21 libc/posix libc/include
+mkdir regex regex/posix
+cd libc/posix
+cp regcomp.c regex.c regex_internal.c regex_internal.h regexec.c $OLDPWD/regex/
+cp regex.h $OLDPWD/regex/posix/
+cd -
+cp libc/include/regex.h regex/
+cd regex
+cvs import src/gnu/lib/libregex FSF fedora-glibc-2_3_4-21
diff --git a/gnu/lib/libregex/Makefile b/gnu/lib/libregex/Makefile
new file mode 100644
index 0000000..39692d4
--- /dev/null
+++ b/gnu/lib/libregex/Makefile
@@ -0,0 +1,28 @@
+# $FreeBSD$
+
+SUBDIR= doc
+
+LIB= gnuregex
+SHLIB_MAJOR= 5
+
+SRCS= gnuregex.c
+INCSGROUPS= INCS WRINCS PXINCS
+INCS= regex.h.patched
+INCSNAME= regex.h
+INCSDIR= ${INCLUDEDIR}/gnu
+WRINCS= gnuregex.h
+PXINCS= posix/regex.h
+PXINCSDIR= ${INCSDIR}/posix
+
+CFLAGS+=-DHAVE_CONFIG_H -I${.CURDIR}
+
+CLEANFILES= regex.h.patched gnuregex.c
+regex.h.patched: regex.h
+ sed 's=<posix/regex\.h>=<gnu/posix/regex.h>=g' \
+ < ${.ALLSRC} > ${.TARGET}
+
+gnuregex.c: regex.c
+ sed 's=<regex\.h>=<gnu/regex.h>=g' \
+ < ${.ALLSRC} > ${.TARGET}
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libregex/config.h b/gnu/lib/libregex/config.h
new file mode 100644
index 0000000..bf7f0a0
--- /dev/null
+++ b/gnu/lib/libregex/config.h
@@ -0,0 +1,12 @@
+/* $FreeBSD$ */
+
+#define _REGEX_RE_COMP 1
+#define HAVE_LANGINFO_H 1
+#define HAVE_LANGINFO_CODESET 1
+#define HAVE_LOCALE_H 1
+#define HAVE_WCHAR_H 1
+#define HAVE_WCTYPE_H 1
+#define HAVE_ISBLANK 1
+#define HAVE_WCRTOMB 1
+#define HAVE_MBRTOWC 1
+#define HAVE_WCSCOLL 1
diff --git a/gnu/lib/libregex/doc/Makefile b/gnu/lib/libregex/doc/Makefile
new file mode 100644
index 0000000..b812f44
--- /dev/null
+++ b/gnu/lib/libregex/doc/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+INFO = regex
+INFOSECTION= "Programming & development tools."
+INFOENTRY_regex= "* Regex: (regex). Regular expression library."
+
+CLEANFILES += regex.texi
+
+regex.texi: xregex.texi ../regex.h
+ awk -f ${.CURDIR}/include.awk -v source=${.CURDIR}/../regex.h \
+ < ${.CURDIR}/xregex.texi \
+ | expand >$@
+
+.include <bsd.info.mk>
diff --git a/gnu/lib/libregex/doc/include.awk b/gnu/lib/libregex/doc/include.awk
new file mode 100644
index 0000000..a1df3f8
--- /dev/null
+++ b/gnu/lib/libregex/doc/include.awk
@@ -0,0 +1,19 @@
+# Assume `source' is set with -vsource=filename on the command line.
+#
+/^\[\[\[/ { inclusion = $2; # name of the thing to include.
+ printing = 0;
+ while ((getline line < source) > 0)
+ {
+ if (match (line, "\\[\\[\\[end " inclusion "\\]\\]\\]"))
+ printing = 0;
+
+ if (printing)
+ print line;
+
+ if (match (line,"\\[\\[\\[begin " inclusion "\\]\\]\\]"))
+ printing = 1;
+ }
+ close (source);
+ next;
+ }
+ { print }
diff --git a/gnu/lib/libregex/doc/xregex.texi b/gnu/lib/libregex/doc/xregex.texi
new file mode 100644
index 0000000..fe01e4e
--- /dev/null
+++ b/gnu/lib/libregex/doc/xregex.texi
@@ -0,0 +1,3021 @@
+\input texinfo
+@c %**start of header
+@setfilename regex.info
+@settitle Regex
+@c %**end of header
+
+@c \\{fill-paragraph} works better (for me, anyway) if the text in the
+@c source file isn't indented.
+@paragraphindent 2
+
+@c Define a new index for our magic constants.
+@defcodeindex cn
+
+@c Put everything in one index (arbitrarily chosen to be the concept index).
+@syncodeindex cn cp
+@syncodeindex ky cp
+@syncodeindex pg cp
+@syncodeindex tp cp
+@syncodeindex vr cp
+
+@c Here is what we use in the Info `dir' file:
+@c * Regex: (regex). Regular expression library.
+
+
+@ifinfo
+This file documents the GNU regular expression library.
+
+Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+section entitled ``GNU General Public License'' is included exactly as
+in the original, and provided that the entire resulting derived work is
+distributed under the terms of a permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the section entitled ``GNU General Public License'' may be
+included in a translation approved by the Free Software Foundation
+instead of in the original English.
+@end ifinfo
+
+
+@titlepage
+
+@title Regex
+@subtitle edition 0.12a
+@subtitle 19 September 1992
+@author Kathryn A. Hargreaves
+@author Karl Berry
+
+@page
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992 Free Software Foundation.
+
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+section entitled ``GNU General Public License'' is included exactly as
+in the original, and provided that the entire resulting derived work is
+distributed under the terms of a permission notice identical to this
+one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the section entitled ``GNU General Public License'' may be
+included in a translation approved by the Free Software Foundation
+instead of in the original English.
+
+@end titlepage
+
+
+@ifinfo
+@node Top, Overview, (dir), (dir)
+@top Regular Expression Library
+
+This manual documents how to program with the GNU regular expression
+library. This is edition 0.12a of the manual, 19 September 1992.
+
+The first part of this master menu lists the major nodes in this Info
+document, including the index. The rest of the menu lists all the
+lower level nodes in the document.
+
+@menu
+* Overview::
+* Regular Expression Syntax::
+* Common Operators::
+* GNU Operators::
+* GNU Emacs Operators::
+* What Gets Matched?::
+* Programming with Regex::
+* Copying:: Copying and sharing Regex.
+* Index:: General index.
+ --- The Detailed Node Listing ---
+
+Regular Expression Syntax
+
+* Syntax Bits::
+* Predefined Syntaxes::
+* Collating Elements vs. Characters::
+* The Backslash Character::
+
+Common Operators
+
+* Match-self Operator:: Ordinary characters.
+* Match-any-character Operator:: .
+* Concatenation Operator:: Juxtaposition.
+* Repetition Operators:: * + ? @{@}
+* Alternation Operator:: |
+* List Operators:: [...] [^...]
+* Grouping Operators:: (...)
+* Back-reference Operator:: \digit
+* Anchoring Operators:: ^ $
+
+Repetition Operators
+
+* Match-zero-or-more Operator:: *
+* Match-one-or-more Operator:: +
+* Match-zero-or-one Operator:: ?
+* Interval Operators:: @{@}
+
+List Operators (@code{[} @dots{} @code{]} and @code{[^} @dots{} @code{]})
+
+* Character Class Operators:: [:class:]
+* Range Operator:: start-end
+
+Anchoring Operators
+
+* Match-beginning-of-line Operator:: ^
+* Match-end-of-line Operator:: $
+
+GNU Operators
+
+* Word Operators::
+* Buffer Operators::
+
+Word Operators
+
+* Non-Emacs Syntax Tables::
+* Match-word-boundary Operator:: \b
+* Match-within-word Operator:: \B
+* Match-beginning-of-word Operator:: \<
+* Match-end-of-word Operator:: \>
+* Match-word-constituent Operator:: \w
+* Match-non-word-constituent Operator:: \W
+
+Buffer Operators
+
+* Match-beginning-of-buffer Operator:: \`
+* Match-end-of-buffer Operator:: \'
+
+GNU Emacs Operators
+
+* Syntactic Class Operators::
+
+Syntactic Class Operators
+
+* Emacs Syntax Tables::
+* Match-syntactic-class Operator:: \sCLASS
+* Match-not-syntactic-class Operator:: \SCLASS
+
+Programming with Regex
+
+* GNU Regex Functions::
+* POSIX Regex Functions::
+* BSD Regex Functions::
+
+GNU Regex Functions
+
+* GNU Pattern Buffers:: The re_pattern_buffer type.
+* GNU Regular Expression Compiling:: re_compile_pattern ()
+* GNU Matching:: re_match ()
+* GNU Searching:: re_search ()
+* Matching/Searching with Split Data:: re_match_2 (), re_search_2 ()
+* Searching with Fastmaps:: re_compile_fastmap ()
+* GNU Translate Tables:: The `translate' field.
+* Using Registers:: The re_registers type and related fns.
+* Freeing GNU Pattern Buffers:: regfree ()
+
+POSIX Regex Functions
+
+* POSIX Pattern Buffers:: The regex_t type.
+* POSIX Regular Expression Compiling:: regcomp ()
+* POSIX Matching:: regexec ()
+* Reporting Errors:: regerror ()
+* Using Byte Offsets:: The regmatch_t type.
+* Freeing POSIX Pattern Buffers:: regfree ()
+
+BSD Regex Functions
+
+* BSD Regular Expression Compiling:: re_comp ()
+* BSD Searching:: re_exec ()
+@end menu
+@end ifinfo
+@node Overview, Regular Expression Syntax, Top, Top
+@chapter Overview
+
+A @dfn{regular expression} (or @dfn{regexp}, or @dfn{pattern}) is a text
+string that describes some (mathematical) set of strings. A regexp
+@var{r} @dfn{matches} a string @var{s} if @var{s} is in the set of
+strings described by @var{r}.
+
+Using the Regex library, you can:
+
+@itemize @bullet
+
+@item
+see if a string matches a specified pattern as a whole, and
+
+@item
+search within a string for a substring matching a specified pattern.
+
+@end itemize
+
+Some regular expressions match only one string, i.e., the set they
+describe has only one member. For example, the regular expression
+@samp{foo} matches the string @samp{foo} and no others. Other regular
+expressions match more than one string, i.e., the set they describe has
+more than one member. For example, the regular expression @samp{f*}
+matches the set of strings made up of any number (including zero) of
+@samp{f}s. As you can see, some characters in regular expressions match
+themselves (such as @samp{f}) and some don't (such as @samp{*}); the
+ones that don't match themselves instead let you specify patterns that
+describe many different strings.
+
+To either match or search for a regular expression with the Regex
+library functions, you must first compile it with a Regex pattern
+compiling function. A @dfn{compiled pattern} is a regular expression
+converted to the internal format used by the library functions. Once
+you've compiled a pattern, you can use it for matching or searching any
+number of times.
+
+The Regex library consists of two source files: @file{regex.h} and
+@file{regex.c}.
+@pindex regex.h
+@pindex regex.c
+Regex provides three groups of functions with which you can operate on
+regular expressions. One group---the @sc{gnu} group---is more powerful
+but not completely compatible with the other two, namely the @sc{posix}
+and Berkeley @sc{unix} groups; its interface was designed specifically
+for @sc{gnu}. The other groups have the same interfaces as do the
+regular expression functions in @sc{posix} and Berkeley
+@sc{unix}.
+
+We wrote this chapter with programmers in mind, not users of
+programs---such as Emacs---that use Regex. We describe the Regex
+library in its entirety, not how to write regular expressions that a
+particular program understands.
+
+
+@node Regular Expression Syntax, Common Operators, Overview, Top
+@chapter Regular Expression Syntax
+
+@cindex regular expressions, syntax of
+@cindex syntax of regular expressions
+
+@dfn{Characters} are things you can type. @dfn{Operators} are things in
+a regular expression that match one or more characters. You compose
+regular expressions from operators, which in turn you specify using one
+or more characters.
+
+Most characters represent what we call the match-self operator, i.e.,
+they match themselves; we call these characters @dfn{ordinary}. Other
+characters represent either all or parts of fancier operators; e.g.,
+@samp{.} represents what we call the match-any-character operator
+(which, no surprise, matches (almost) any character); we call these
+characters @dfn{special}. Two different things determine what
+characters represent what operators:
+
+@enumerate
+@item
+the regular expression syntax your program has told the Regex library to
+recognize, and
+
+@item
+the context of the character in the regular expression.
+@end enumerate
+
+In the following sections, we describe these things in more detail.
+
+@menu
+* Syntax Bits::
+* Predefined Syntaxes::
+* Collating Elements vs. Characters::
+* The Backslash Character::
+@end menu
+
+
+@node Syntax Bits, Predefined Syntaxes, , Regular Expression Syntax
+@section Syntax Bits
+
+@cindex syntax bits
+
+In any particular syntax for regular expressions, some characters are
+always special, others are sometimes special, and others are never
+special. The particular syntax that Regex recognizes for a given
+regular expression depends on the value in the @code{syntax} field of
+the pattern buffer of that regular expression.
+
+You get a pattern buffer by compiling a regular expression. @xref{GNU
+Pattern Buffers}, and @ref{POSIX Pattern Buffers}, for more information
+on pattern buffers. @xref{GNU Regular Expression Compiling}, @ref{POSIX
+Regular Expression Compiling}, and @ref{BSD Regular Expression
+Compiling}, for more information on compiling.
+
+Regex considers the value of the @code{syntax} field to be a collection
+of bits; we refer to these bits as @dfn{syntax bits}. In most cases,
+they affect what characters represent what operators. We describe the
+meanings of the operators to which we refer in @ref{Common Operators},
+@ref{GNU Operators}, and @ref{GNU Emacs Operators}.
+
+For reference, here is the complete list of syntax bits, in alphabetical
+order:
+
+@table @code
+
+@cnindex RE_BACKSLASH_ESCAPE_IN_LIST
+@item RE_BACKSLASH_ESCAPE_IN_LISTS
+If this bit is set, then @samp{\} inside a list (@pxref{List Operators}
+quotes (makes ordinary, if it's special) the following character; if
+this bit isn't set, then @samp{\} is an ordinary character inside lists.
+(@xref{The Backslash Character}, for what `\' does outside of lists.)
+
+@cnindex RE_BK_PLUS_QM
+@item RE_BK_PLUS_QM
+If this bit is set, then @samp{\+} represents the match-one-or-more
+operator and @samp{\?} represents the match-zero-or-more operator; if
+this bit isn't set, then @samp{+} represents the match-one-or-more
+operator and @samp{?} represents the match-zero-or-one operator. This
+bit is irrelevant if @code{RE_LIMITED_OPS} is set.
+
+@cnindex RE_CHAR_CLASSES
+@item RE_CHAR_CLASSES
+If this bit is set, then you can use character classes in lists; if this
+bit isn't set, then you can't.
+
+@cnindex RE_CONTEXT_INDEP_ANCHORS
+@item RE_CONTEXT_INDEP_ANCHORS
+If this bit is set, then @samp{^} and @samp{$} are special anywhere outside
+a list; if this bit isn't set, then these characters are special only in
+certain contexts. @xref{Match-beginning-of-line Operator}, and
+@ref{Match-end-of-line Operator}.
+
+@cnindex RE_CONTEXT_INDEP_OPS
+@item RE_CONTEXT_INDEP_OPS
+If this bit is set, then certain characters are special anywhere outside
+a list; if this bit isn't set, then those characters are special only in
+some contexts and are ordinary elsewhere. Specifically, if this bit
+isn't set then @samp{*}, and (if the syntax bit @code{RE_LIMITED_OPS}
+isn't set) @samp{+} and @samp{?} (or @samp{\+} and @samp{\?}, depending
+on the syntax bit @code{RE_BK_PLUS_QM}) represent repetition operators
+only if they're not first in a regular expression or just after an
+open-group or alternation operator. The same holds for @samp{@{} (or
+@samp{\@{}, depending on the syntax bit @code{RE_NO_BK_BRACES}) if
+it is the beginning of a valid interval and the syntax bit
+@code{RE_INTERVALS} is set.
+
+@cnindex RE_CONTEXT_INVALID_OPS
+@item RE_CONTEXT_INVALID_OPS
+If this bit is set, then repetition and alternation operators can't be
+in certain positions within a regular expression. Specifically, the
+regular expression is invalid if it has:
+
+@itemize @bullet
+
+@item
+a repetition operator first in the regular expression or just after a
+match-beginning-of-line, open-group, or alternation operator; or
+
+@item
+an alternation operator first or last in the regular expression, just
+before a match-end-of-line operator, or just after an alternation or
+open-group operator.
+
+@end itemize
+
+If this bit isn't set, then you can put the characters representing the
+repetition and alternation characters anywhere in a regular expression.
+Whether or not they will in fact be operators in certain positions
+depends on other syntax bits.
+
+@cnindex RE_DOT_NEWLINE
+@item RE_DOT_NEWLINE
+If this bit is set, then the match-any-character operator matches
+a newline; if this bit isn't set, then it doesn't.
+
+@cnindex RE_DOT_NOT_NULL
+@item RE_DOT_NOT_NULL
+If this bit is set, then the match-any-character operator doesn't match
+a null character; if this bit isn't set, then it does.
+
+@cnindex RE_INTERVALS
+@item RE_INTERVALS
+If this bit is set, then Regex recognizes interval operators; if this bit
+isn't set, then it doesn't.
+
+@cnindex RE_LIMITED_OPS
+@item RE_LIMITED_OPS
+If this bit is set, then Regex doesn't recognize the match-one-or-more,
+match-zero-or-one or alternation operators; if this bit isn't set, then
+it does.
+
+@cnindex RE_NEWLINE_ALT
+@item RE_NEWLINE_ALT
+If this bit is set, then newline represents the alternation operator; if
+this bit isn't set, then newline is ordinary.
+
+@cnindex RE_NO_BK_BRACES
+@item RE_NO_BK_BRACES
+If this bit is set, then @samp{@{} represents the open-interval operator
+and @samp{@}} represents the close-interval operator; if this bit isn't
+set, then @samp{\@{} represents the open-interval operator and
+@samp{\@}} represents the close-interval operator. This bit is relevant
+only if @code{RE_INTERVALS} is set.
+
+@cnindex RE_NO_BK_PARENS
+@item RE_NO_BK_PARENS
+If this bit is set, then @samp{(} represents the open-group operator and
+@samp{)} represents the close-group operator; if this bit isn't set, then
+@samp{\(} represents the open-group operator and @samp{\)} represents
+the close-group operator.
+
+@cnindex RE_NO_BK_REFS
+@item RE_NO_BK_REFS
+If this bit is set, then Regex doesn't recognize @samp{\}@var{digit} as
+the back reference operator; if this bit isn't set, then it does.
+
+@cnindex RE_NO_BK_VBAR
+@item RE_NO_BK_VBAR
+If this bit is set, then @samp{|} represents the alternation operator;
+if this bit isn't set, then @samp{\|} represents the alternation
+operator. This bit is irrelevant if @code{RE_LIMITED_OPS} is set.
+
+@cnindex RE_NO_EMPTY_RANGES
+@item RE_NO_EMPTY_RANGES
+If this bit is set, then a regular expression with a range whose ending
+point collates lower than its starting point is invalid; if this bit
+isn't set, then Regex considers such a range to be empty.
+
+@cnindex RE_UNMATCHED_RIGHT_PAREN_ORD
+@item RE_UNMATCHED_RIGHT_PAREN_ORD
+If this bit is set and the regular expression has no matching open-group
+operator, then Regex considers what would otherwise be a close-group
+operator (based on how @code{RE_NO_BK_PARENS} is set) to match @samp{)}.
+
+@end table
+
+
+@node Predefined Syntaxes, Collating Elements vs. Characters, Syntax Bits, Regular Expression Syntax
+@section Predefined Syntaxes
+
+If you're programming with Regex, you can set a pattern buffer's
+(@pxref{GNU Pattern Buffers}, and @ref{POSIX Pattern Buffers})
+@code{syntax} field either to an arbitrary combination of syntax bits
+(@pxref{Syntax Bits}) or else to the configurations defined by Regex.
+These configurations define the syntaxes used by certain
+programs---@sc{gnu} Emacs,
+@cindex Emacs
+@sc{posix} Awk,
+@cindex POSIX Awk
+traditional Awk,
+@cindex Awk
+Grep,
+@cindex Grep
+@cindex Egrep
+Egrep---in addition to syntaxes for @sc{posix} basic and extended
+regular expressions.
+
+The predefined syntaxes--taken directly from @file{regex.h}---are:
+
+@example
+[[[ syntaxes ]]]
+@end example
+
+@node Collating Elements vs. Characters, The Backslash Character, Predefined Syntaxes, Regular Expression Syntax
+@section Collating Elements vs.@: Characters
+
+@sc{posix} generalizes the notion of a character to that of a
+collating element. It defines a @dfn{collating element} to be ``a
+sequence of one or more bytes defined in the current collating sequence
+as a unit of collation.''
+
+This generalizes the notion of a character in
+two ways. First, a single character can map into two or more collating
+elements. For example, the German
+@tex
+`\ss'
+@end tex
+@ifinfo
+``es-zet''
+@end ifinfo
+collates as the collating element @samp{s} followed by another collating
+element @samp{s}. Second, two or more characters can map into one
+collating element. For example, the Spanish @samp{ll} collates after
+@samp{l} and before @samp{m}.
+
+Since @sc{posix}'s ``collating element'' preserves the essential idea of
+a ``character,'' we use the latter, more familiar, term in this document.
+
+@node The Backslash Character, , Collating Elements vs. Characters, Regular Expression Syntax
+@section The Backslash Character
+
+@cindex \
+The @samp{\} character has one of four different meanings, depending on
+the context in which you use it and what syntax bits are set
+(@pxref{Syntax Bits}). It can: 1) stand for itself, 2) quote the next
+character, 3) introduce an operator, or 4) do nothing.
+
+@enumerate
+@item
+It stands for itself inside a list
+(@pxref{List Operators}) if the syntax bit
+@code{RE_BACKSLASH_ESCAPE_IN_LISTS} is not set. For example, @samp{[\]}
+would match @samp{\}.
+
+@item
+It quotes (makes ordinary, if it's special) the next character when you
+use it either:
+
+@itemize @bullet
+@item
+outside a list,@footnote{Sometimes
+you don't have to explicitly quote special characters to make
+them ordinary. For instance, most characters lose any special meaning
+inside a list (@pxref{List Operators}). In addition, if the syntax bits
+@code{RE_CONTEXT_INVALID_OPS} and @code{RE_CONTEXT_INDEP_OPS}
+aren't set, then (for historical reasons) the matcher considers special
+characters ordinary if they are in contexts where the operations they
+represent make no sense; for example, then the match-zero-or-more
+operator (represented by @samp{*}) matches itself in the regular
+expression @samp{*foo} because there is no preceding expression on which
+it can operate. It is poor practice, however, to depend on this
+behavior; if you want a special character to be ordinary outside a list,
+it's better to always quote it, regardless.} or
+
+@item
+inside a list and the syntax bit @code{RE_BACKSLASH_ESCAPE_IN_LISTS} is set.
+
+@end itemize
+
+@item
+It introduces an operator when followed by certain ordinary
+characters---sometimes only when certain syntax bits are set. See the
+cases @code{RE_BK_PLUS_QM}, @code{RE_NO_BK_BRACES}, @code{RE_NO_BK_VAR},
+@code{RE_NO_BK_PARENS}, @code{RE_NO_BK_REF} in @ref{Syntax Bits}. Also:
+
+@itemize @bullet
+@item
+@samp{\b} represents the match-word-boundary operator
+(@pxref{Match-word-boundary Operator}).
+
+@item
+@samp{\B} represents the match-within-word operator
+(@pxref{Match-within-word Operator}).
+
+@item
+@samp{\<} represents the match-beginning-of-word operator @*
+(@pxref{Match-beginning-of-word Operator}).
+
+@item
+@samp{\>} represents the match-end-of-word operator
+(@pxref{Match-end-of-word Operator}).
+
+@item
+@samp{\w} represents the match-word-constituent operator
+(@pxref{Match-word-constituent Operator}).
+
+@item
+@samp{\W} represents the match-non-word-constituent operator
+(@pxref{Match-non-word-constituent Operator}).
+
+@item
+@samp{\`} represents the match-beginning-of-buffer
+operator and @samp{\'} represents the match-end-of-buffer operator
+(@pxref{Buffer Operators}).
+
+@item
+If Regex was compiled with the C preprocessor symbol @code{emacs}
+defined, then @samp{\s@var{class}} represents the match-syntactic-class
+operator and @samp{\S@var{class}} represents the
+match-not-syntactic-class operator (@pxref{Syntactic Class Operators}).
+
+@end itemize
+
+@item
+In all other cases, Regex ignores @samp{\}. For example,
+@samp{\n} matches @samp{n}.
+
+@end enumerate
+
+@node Common Operators, GNU Operators, Regular Expression Syntax, Top
+@chapter Common Operators
+
+You compose regular expressions from operators. In the following
+sections, we describe the regular expression operators specified by
+@sc{posix}; @sc{gnu} also uses these. Most operators have more than one
+representation as characters. @xref{Regular Expression Syntax}, for
+what characters represent what operators under what circumstances.
+
+For most operators that can be represented in two ways, one
+representation is a single character and the other is that character
+preceded by @samp{\}. For example, either @samp{(} or @samp{\(}
+represents the open-group operator. Which one does depends on the
+setting of a syntax bit, in this case @code{RE_NO_BK_PARENS}. Why is
+this so? Historical reasons dictate some of the varying
+representations, while @sc{posix} dictates others.
+
+Finally, almost all characters lose any special meaning inside a list
+(@pxref{List Operators}).
+
+@menu
+* Match-self Operator:: Ordinary characters.
+* Match-any-character Operator:: .
+* Concatenation Operator:: Juxtaposition.
+* Repetition Operators:: * + ? @{@}
+* Alternation Operator:: |
+* List Operators:: [...] [^...]
+* Grouping Operators:: (...)
+* Back-reference Operator:: \digit
+* Anchoring Operators:: ^ $
+@end menu
+
+@node Match-self Operator, Match-any-character Operator, , Common Operators
+@section The Match-self Operator (@var{ordinary character})
+
+This operator matches the character itself. All ordinary characters
+(@pxref{Regular Expression Syntax}) represent this operator. For
+example, @samp{f} is always an ordinary character, so the regular
+expression @samp{f} matches only the string @samp{f}. In
+particular, it does @emph{not} match the string @samp{ff}.
+
+@node Match-any-character Operator, Concatenation Operator, Match-self Operator, Common Operators
+@section The Match-any-character Operator (@code{.})
+
+@cindex @samp{.}
+
+This operator matches any single printing or nonprinting character
+except it won't match a:
+
+@table @asis
+@item newline
+if the syntax bit @code{RE_DOT_NEWLINE} isn't set.
+
+@item null
+if the syntax bit @code{RE_DOT_NOT_NULL} is set.
+
+@end table
+
+The @samp{.} (period) character represents this operator. For example,
+@samp{a.b} matches any three-character string beginning with @samp{a}
+and ending with @samp{b}.
+
+@node Concatenation Operator, Repetition Operators, Match-any-character Operator, Common Operators
+@section The Concatenation Operator
+
+This operator concatenates two regular expressions @var{a} and @var{b}.
+No character represents this operator; you simply put @var{b} after
+@var{a}. The result is a regular expression that will match a string if
+@var{a} matches its first part and @var{b} matches the rest. For
+example, @samp{xy} (two match-self operators) matches @samp{xy}.
+
+@node Repetition Operators, Alternation Operator, Concatenation Operator, Common Operators
+@section Repetition Operators
+
+Repetition operators repeat the preceding regular expression a specified
+number of times.
+
+@menu
+* Match-zero-or-more Operator:: *
+* Match-one-or-more Operator:: +
+* Match-zero-or-one Operator:: ?
+* Interval Operators:: @{@}
+@end menu
+
+@node Match-zero-or-more Operator, Match-one-or-more Operator, , Repetition Operators
+@subsection The Match-zero-or-more Operator (@code{*})
+
+@cindex @samp{*}
+
+This operator repeats the smallest possible preceding regular expression
+as many times as necessary (including zero) to match the pattern.
+@samp{*} represents this operator. For example, @samp{o*}
+matches any string made up of zero or more @samp{o}s. Since this
+operator operates on the smallest preceding regular expression,
+@samp{fo*} has a repeating @samp{o}, not a repeating @samp{fo}. So,
+@samp{fo*} matches @samp{f}, @samp{fo}, @samp{foo}, and so on.
+
+Since the match-zero-or-more operator is a suffix operator, it may be
+useless as such when no regular expression precedes it. This is the
+case when it:
+
+@itemize @bullet
+@item
+is first in a regular expression, or
+
+@item
+follows a match-beginning-of-line, open-group, or alternation
+operator.
+
+@end itemize
+
+@noindent
+Three different things can happen in these cases:
+
+@enumerate
+@item
+If the syntax bit @code{RE_CONTEXT_INVALID_OPS} is set, then the
+regular expression is invalid.
+
+@item
+If @code{RE_CONTEXT_INVALID_OPS} isn't set, but
+@code{RE_CONTEXT_INDEP_OPS} is, then @samp{*} represents the
+match-zero-or-more operator (which then operates on the empty string).
+
+@item
+Otherwise, @samp{*} is ordinary.
+
+@end enumerate
+
+@cindex backtracking
+The matcher processes a match-zero-or-more operator by first matching as
+many repetitions of the smallest preceding regular expression as it can.
+Then it continues to match the rest of the pattern.
+
+If it can't match the rest of the pattern, it backtracks (as many times
+as necessary), each time discarding one of the matches until it can
+either match the entire pattern or be certain that it cannot get a
+match. For example, when matching @samp{ca*ar} against @samp{caaar},
+the matcher first matches all three @samp{a}s of the string with the
+@samp{a*} of the regular expression. However, it cannot then match the
+final @samp{ar} of the regular expression against the final @samp{r} of
+the string. So it backtracks, discarding the match of the last @samp{a}
+in the string. It can then match the remaining @samp{ar}.
+
+
+@node Match-one-or-more Operator, Match-zero-or-one Operator, Match-zero-or-more Operator, Repetition Operators
+@subsection The Match-one-or-more Operator (@code{+} or @code{\+})
+
+@cindex @samp{+}
+
+If the syntax bit @code{RE_LIMITED_OPS} is set, then Regex doesn't recognize
+this operator. Otherwise, if the syntax bit @code{RE_BK_PLUS_QM} isn't
+set, then @samp{+} represents this operator; if it is, then @samp{\+}
+does.
+
+This operator is similar to the match-zero-or-more operator except that
+it repeats the preceding regular expression at least once;
+@pxref{Match-zero-or-more Operator}, for what it operates on, how some
+syntax bits affect it, and how Regex backtracks to match it.
+
+For example, supposing that @samp{+} represents the match-one-or-more
+operator; then @samp{ca+r} matches, e.g., @samp{car} and
+@samp{caaaar}, but not @samp{cr}.
+
+@node Match-zero-or-one Operator, Interval Operators, Match-one-or-more Operator, Repetition Operators
+@subsection The Match-zero-or-one Operator (@code{?} or @code{\?})
+@cindex @samp{?}
+
+If the syntax bit @code{RE_LIMITED_OPS} is set, then Regex doesn't
+recognize this operator. Otherwise, if the syntax bit
+@code{RE_BK_PLUS_QM} isn't set, then @samp{?} represents this operator;
+if it is, then @samp{\?} does.
+
+This operator is similar to the match-zero-or-more operator except that
+it repeats the preceding regular expression once or not at all;
+@pxref{Match-zero-or-more Operator}, to see what it operates on, how
+some syntax bits affect it, and how Regex backtracks to match it.
+
+For example, supposing that @samp{?} represents the match-zero-or-one
+operator; then @samp{ca?r} matches both @samp{car} and @samp{cr}, but
+nothing else.
+
+@node Interval Operators, , Match-zero-or-one Operator, Repetition Operators
+@subsection Interval Operators (@code{@{} @dots{} @code{@}} or @code{\@{} @dots{} @code{\@}})
+
+@cindex interval expression
+@cindex @samp{@{}
+@cindex @samp{@}}
+@cindex @samp{\@{}
+@cindex @samp{\@}}
+
+If the syntax bit @code{RE_INTERVALS} is set, then Regex recognizes
+@dfn{interval expressions}. They repeat the smallest possible preceding
+regular expression a specified number of times.
+
+If the syntax bit @code{RE_NO_BK_BRACES} is set, @samp{@{} represents
+the @dfn{open-interval operator} and @samp{@}} represents the
+@dfn{close-interval operator} ; otherwise, @samp{\@{} and @samp{\@}} do.
+
+Specifically, supposing that @samp{@{} and @samp{@}} represent the
+open-interval and close-interval operators; then:
+
+@table @code
+@item @{@var{count}@}
+matches exactly @var{count} occurrences of the preceding regular
+expression.
+
+@item @{@var{min,}@}
+matches @var{min} or more occurrences of the preceding regular
+expression.
+
+@item @{@var{min, max}@}
+matches at least @var{min} but no more than @var{max} occurrences of
+the preceding regular expression.
+
+@end table
+
+The interval expression (but not necessarily the regular expression that
+contains it) is invalid if:
+
+@itemize @bullet
+@item
+@var{min} is greater than @var{max}, or
+
+@item
+any of @var{count}, @var{min}, or @var{max} are outside the range
+zero to @code{RE_DUP_MAX} (which symbol @file{regex.h}
+defines).
+
+@end itemize
+
+If the interval expression is invalid and the syntax bit
+@code{RE_NO_BK_BRACES} is set, then Regex considers all the
+characters in the would-be interval to be ordinary. If that bit
+isn't set, then the regular expression is invalid.
+
+If the interval expression is valid but there is no preceding regular
+expression on which to operate, then if the syntax bit
+@code{RE_CONTEXT_INVALID_OPS} is set, the regular expression is invalid.
+If that bit isn't set, then Regex considers all the characters---other
+than backslashes, which it ignores---in the would-be interval to be
+ordinary.
+
+
+@node Alternation Operator, List Operators, Repetition Operators, Common Operators
+@section The Alternation Operator (@code{|} or @code{\|})
+
+@kindex |
+@kindex \|
+@cindex alternation operator
+@cindex or operator
+
+If the syntax bit @code{RE_LIMITED_OPS} is set, then Regex doesn't
+recognize this operator. Otherwise, if the syntax bit
+@code{RE_NO_BK_VBAR} is set, then @samp{|} represents this operator;
+otherwise, @samp{\|} does.
+
+Alternatives match one of a choice of regular expressions:
+if you put the character(s) representing the alternation operator between
+any two regular expressions @var{a} and @var{b}, the result matches
+the union of the strings that @var{a} and @var{b} match. For
+example, supposing that @samp{|} is the alternation operator, then
+@samp{foo|bar|quux} would match any of @samp{foo}, @samp{bar} or
+@samp{quux}.
+
+@ignore
+@c Nobody needs to disallow empty alternatives any more.
+If the syntax bit @code{RE_NO_EMPTY_ALTS} is set, then if either of the regular
+expressions @var{a} or @var{b} is empty, the
+regular expression is invalid. More precisely, if this syntax bit is
+set, then the alternation operator can't:
+
+@itemize @bullet
+@item
+be first or last in a regular expression;
+
+@item
+follow either another alternation operator or an open-group operator
+(@pxref{Grouping Operators}); or
+
+@item
+precede a close-group operator.
+
+@end itemize
+
+@noindent
+For example, supposing @samp{(} and @samp{)} represent the open and
+close-group operators, then @samp{|foo}, @samp{foo|}, @samp{foo||bar},
+@samp{foo(|bar)}, and @samp{(foo|)bar} would all be invalid.
+@end ignore
+
+The alternation operator operates on the @emph{largest} possible
+surrounding regular expressions. (Put another way, it has the lowest
+precedence of any regular expression operator.)
+Thus, the only way you can
+delimit its arguments is to use grouping. For example, if @samp{(} and
+@samp{)} are the open and close-group operators, then @samp{fo(o|b)ar}
+would match either @samp{fooar} or @samp{fobar}. (@samp{foo|bar} would
+match @samp{foo} or @samp{bar}.)
+
+@cindex backtracking
+The matcher usually tries all combinations of alternatives so as to
+match the longest possible string. For example, when matching
+@samp{(fooq|foo)*(qbarquux|bar)} against @samp{fooqbarquux}, it cannot
+take, say, the first (``depth-first'') combination it could match, since
+then it would be content to match just @samp{fooqbar}.
+
+@comment xx something about leftmost-longest
+
+
+@node List Operators, Grouping Operators, Alternation Operator, Common Operators
+@section List Operators (@code{[} @dots{} @code{]} and @code{[^} @dots{} @code{]})
+
+@cindex matching list
+@cindex @samp{[}
+@cindex @samp{]}
+@cindex @samp{^}
+@cindex @samp{-}
+@cindex @samp{\}
+@cindex @samp{[^}
+@cindex nonmatching list
+@cindex matching newline
+@cindex bracket expression
+
+@dfn{Lists}, also called @dfn{bracket expressions}, are a set of one or
+more items. An @dfn{item} is a character,
+@ignore
+(These get added when they get implemented.)
+a collating symbol, an equivalence class expression,
+@end ignore
+a character class expression, or a range expression. The syntax bits
+affect which kinds of items you can put in a list. We explain the last
+two items in subsections below. Empty lists are invalid.
+
+A @dfn{matching list} matches a single character represented by one of
+the list items. You form a matching list by enclosing one or more items
+within an @dfn{open-matching-list operator} (represented by @samp{[})
+and a @dfn{close-list operator} (represented by @samp{]}).
+
+For example, @samp{[ab]} matches either @samp{a} or @samp{b}.
+@samp{[ad]*} matches the empty string and any string composed of just
+@samp{a}s and @samp{d}s in any order. Regex considers invalid a regular
+expression with a @samp{[} but no matching
+@samp{]}.
+
+@dfn{Nonmatching lists} are similar to matching lists except that they
+match a single character @emph{not} represented by one of the list
+items. You use an @dfn{open-nonmatching-list operator} (represented by
+@samp{[^}@footnote{Regex therefore doesn't consider the @samp{^} to be
+the first character in the list. If you put a @samp{^} character first
+in (what you think is) a matching list, you'll turn it into a
+nonmatching list.}) instead of an open-matching-list operator to start a
+nonmatching list.
+
+For example, @samp{[^ab]} matches any character except @samp{a} or
+@samp{b}.
+
+If the @code{posix_newline} field in the pattern buffer (@pxref{GNU
+Pattern Buffers} is set, then nonmatching lists do not match a newline.
+
+Most characters lose any special meaning inside a list. The special
+characters inside a list follow.
+
+@table @samp
+@item ]
+ends the list if it's not the first list item. So, if you want to make
+the @samp{]} character a list item, you must put it first.
+
+@item \
+quotes the next character if the syntax bit @code{RE_BACKSLASH_ESCAPE_IN_LISTS} is
+set.
+
+@ignore
+Put these in if they get implemented.
+
+@item [.
+represents the open-collating-symbol operator (@pxref{Collating Symbol
+Operators}).
+
+@item .]
+represents the close-collating-symbol operator.
+
+@item [=
+represents the open-equivalence-class operator (@pxref{Equivalence Class
+Operators}).
+
+@item =]
+represents the close-equivalence-class operator.
+
+@end ignore
+
+@item [:
+represents the open-character-class operator (@pxref{Character Class
+Operators}) if the syntax bit @code{RE_CHAR_CLASSES} is set and what
+follows is a valid character class expression.
+
+@item :]
+represents the close-character-class operator if the syntax bit
+@code{RE_CHAR_CLASSES} is set and what precedes it is an
+open-character-class operator followed by a valid character class name.
+
+@item -
+represents the range operator (@pxref{Range Operator}) if it's
+not first or last in a list or the ending point of a range.
+
+@end table
+
+@noindent
+All other characters are ordinary. For example, @samp{[.*]} matches
+@samp{.} and @samp{*}.
+
+@menu
+* Character Class Operators:: [:class:]
+* Range Operator:: start-end
+@end menu
+
+@ignore
+(If collating symbols and equivalence class expressions get implemented,
+then add this.)
+
+node Collating Symbol Operators
+subsubsection Collating Symbol Operators (@code{[.} @dots{} @code{.]})
+
+If the syntax bit @code{XX} is set, then you can represent
+collating symbols inside lists. You form a @dfn{collating symbol} by
+putting a collating element between an @dfn{open-collating-symbol
+operator} and an @dfn{close-collating-symbol operator}. @samp{[.}
+represents the open-collating-symbol operator and @samp{.]} represents
+the close-collating-symbol operator. For example, if @samp{ll} is a
+collating element, then @samp{[[.ll.]]} would match @samp{ll}.
+
+node Equivalence Class Operators
+subsubsection Equivalence Class Operators (@code{[=} @dots{} @code{=]})
+@cindex equivalence class expression in regex
+@cindex @samp{[=} in regex
+@cindex @samp{=]} in regex
+
+If the syntax bit @code{XX} is set, then Regex recognizes equivalence class
+expressions inside lists. A @dfn{equivalence class expression} is a set
+of collating elements which all belong to the same equivalence class.
+You form an equivalence class expression by putting a collating
+element between an @dfn{open-equivalence-class operator} and a
+@dfn{close-equivalence-class operator}. @samp{[=} represents the
+open-equivalence-class operator and @samp{=]} represents the
+close-equivalence-class operator. For example, if @samp{a} and @samp{A}
+were an equivalence class, then both @samp{[[=a=]]} and @samp{[[=A=]]}
+would match both @samp{a} and @samp{A}. If the collating element in an
+equivalence class expression isn't part of an equivalence class, then
+the matcher considers the equivalence class expression to be a collating
+symbol.
+
+@end ignore
+
+@node Character Class Operators, Range Operator, , List Operators
+@subsection Character Class Operators (@code{[:} @dots{} @code{:]})
+
+@cindex character classes
+@cindex @samp{[:} in regex
+@cindex @samp{:]} in regex
+
+If the syntax bit @code{RE_CHARACTER_CLASSES} is set, then Regex
+recognizes character class expressions inside lists. A @dfn{character
+class expression} matches one character from a given class. You form a
+character class expression by putting a character class name between an
+@dfn{open-character-class operator} (represented by @samp{[:}) and a
+@dfn{close-character-class operator} (represented by @samp{:]}). The
+character class names and their meanings are:
+
+@table @code
+
+@item alnum
+letters and digits
+
+@item alpha
+letters
+
+@item blank
+system-dependent; for @sc{gnu}, a space or tab
+
+@item cntrl
+control characters (in the @sc{ascii} encoding, code 0177 and codes
+less than 040)
+
+@item digit
+digits
+
+@item graph
+same as @code{print} except omits space
+
+@item lower
+lowercase letters
+
+@item print
+printable characters (in the @sc{ascii} encoding, space
+tilde---codes 040 through 0176)
+
+@item punct
+neither control nor alphanumeric characters
+
+@item space
+space, carriage return, newline, vertical tab, and form feed
+
+@item upper
+uppercase letters
+
+@item xdigit
+hexadecimal digits: @code{0}--@code{9}, @code{a}--@code{f}, @code{A}--@code{F}
+
+@end table
+
+@noindent
+These correspond to the definitions in the C library's @file{<ctype.h>}
+facility. For example, @samp{[:alpha:]} corresponds to the standard
+facility @code{isalpha}. Regex recognizes character class expressions
+only inside of lists; so @samp{[[:alpha:]]} matches any letter, but
+@samp{[:alpha:]} outside of a bracket expression and not followed by a
+repetition operator matches just itself.
+
+@node Range Operator, , Character Class Operators, List Operators
+@subsection The Range Operator (@code{-})
+
+Regex recognizes @dfn{range expressions} inside a list. They represent
+those characters
+that fall between two elements in the current collating sequence. You
+form a range expression by putting a @dfn{range operator} between two
+@ignore
+(If these get implemented, then substitute this for ``characters.'')
+of any of the following: characters, collating elements, collating symbols,
+and equivalence class expressions. The starting point of the range and
+the ending point of the range don't have to be the same kind of item,
+e.g., the starting point could be a collating element and the ending
+point could be an equivalence class expression. If a range's ending
+point is an equivalence class, then all the collating elements in that
+class will be in the range.
+@end ignore
+characters.@footnote{You can't use a character class for the starting
+or ending point of a range, since a character class is not a single
+character.} @samp{-} represents the range operator. For example,
+@samp{a-f} within a list represents all the characters from @samp{a}
+through @samp{f}
+inclusively.
+
+If the syntax bit @code{RE_NO_EMPTY_RANGES} is set, then if the range's
+ending point collates less than its starting point, the range (and the
+regular expression containing it) is invalid. For example, the regular
+expression @samp{[z-a]} would be invalid. If this bit isn't set, then
+Regex considers such a range to be empty.
+
+Since @samp{-} represents the range operator, if you want to make a
+@samp{-} character itself
+a list item, you must do one of the following:
+
+@itemize @bullet
+@item
+Put the @samp{-} either first or last in the list.
+
+@item
+Include a range whose starting point collates strictly lower than
+@samp{-} and whose ending point collates equal or higher. Unless a
+range is the first item in a list, a @samp{-} can't be its starting
+point, but @emph{can} be its ending point. That is because Regex
+considers @samp{-} to be the range operator unless it is preceded by
+another @samp{-}. For example, in the @sc{ascii} encoding, @samp{)},
+@samp{*}, @samp{+}, @samp{,}, @samp{-}, @samp{.}, and @samp{/} are
+contiguous characters in the collating sequence. You might think that
+@samp{[)-+--/]} has two ranges: @samp{)-+} and @samp{--/}. Rather, it
+has the ranges @samp{)-+} and @samp{+--}, plus the character @samp{/}, so
+it matches, e.g., @samp{,}, not @samp{.}.
+
+@item
+Put a range whose starting point is @samp{-} first in the list.
+
+@end itemize
+
+For example, @samp{[-a-z]} matches a lowercase letter or a hyphen (in
+English, in @sc{ascii}).
+
+
+@node Grouping Operators, Back-reference Operator, List Operators, Common Operators
+@section Grouping Operators (@code{(} @dots{} @code{)} or @code{\(} @dots{} @code{\)})
+
+@kindex (
+@kindex )
+@kindex \(
+@kindex \)
+@cindex grouping
+@cindex subexpressions
+@cindex parenthesizing
+
+A @dfn{group}, also known as a @dfn{subexpression}, consists of an
+@dfn{open-group operator}, any number of other operators, and a
+@dfn{close-group operator}. Regex treats this sequence as a unit, just
+as mathematics and programming languages treat a parenthesized
+expression as a unit.
+
+Therefore, using @dfn{groups}, you can:
+
+@itemize @bullet
+@item
+delimit the argument(s) to an alternation operator (@pxref{Alternation
+Operator}) or a repetition operator (@pxref{Repetition
+Operators}).
+
+@item
+keep track of the indices of the substring that matched a given group.
+@xref{Using Registers}, for a precise explanation.
+This lets you:
+
+@itemize @bullet
+@item
+use the back-reference operator (@pxref{Back-reference Operator}).
+
+@item
+use registers (@pxref{Using Registers}).
+
+@end itemize
+
+@end itemize
+
+If the syntax bit @code{RE_NO_BK_PARENS} is set, then @samp{(} represents
+the open-group operator and @samp{)} represents the
+close-group operator; otherwise, @samp{\(} and @samp{\)} do.
+
+If the syntax bit @code{RE_UNMATCHED_RIGHT_PAREN_ORD} is set and a
+close-group operator has no matching open-group operator, then Regex
+considers it to match @samp{)}.
+
+
+@node Back-reference Operator, Anchoring Operators, Grouping Operators, Common Operators
+@section The Back-reference Operator (@dfn{\}@var{digit})
+
+@cindex back references
+
+If the syntax bit @code{RE_NO_BK_REF} isn't set, then Regex recognizes
+back references. A back reference matches a specified preceding group.
+The back reference operator is represented by @samp{\@var{digit}}
+anywhere after the end of a regular expression's @w{@var{digit}-th}
+group (@pxref{Grouping Operators}).
+
+@var{digit} must be between @samp{1} and @samp{9}. The matcher assigns
+numbers 1 through 9 to the first nine groups it encounters. By using
+one of @samp{\1} through @samp{\9} after the corresponding group's
+close-group operator, you can match a substring identical to the
+one that the group does.
+
+Back references match according to the following (in all examples below,
+@samp{(} represents the open-group, @samp{)} the close-group, @samp{@{}
+the open-interval and @samp{@}} the close-interval operator):
+
+@itemize @bullet
+@item
+If the group matches a substring, the back reference matches an
+identical substring. For example, @samp{(a)\1} matches @samp{aa} and
+@samp{(bana)na\1bo\1} matches @samp{bananabanabobana}. Likewise,
+@samp{(.*)\1} matches any (newline-free if the syntax bit
+@code{RE_DOT_NEWLINE} isn't set) string that is composed of two
+identical halves; the @samp{(.*)} matches the first half and the
+@samp{\1} matches the second half.
+
+@item
+If the group matches more than once (as it might if followed
+by, e.g., a repetition operator), then the back reference matches the
+substring the group @emph{last} matched. For example,
+@samp{((a*)b)*\1\2} matches @samp{aabababa}; first @w{group 1} (the
+outer one) matches @samp{aab} and @w{group 2} (the inner one) matches
+@samp{aa}. Then @w{group 1} matches @samp{ab} and @w{group 2} matches
+@samp{a}. So, @samp{\1} matches @samp{ab} and @samp{\2} matches
+@samp{a}.
+
+@item
+If the group doesn't participate in a match, i.e., it is part of an
+alternative not taken or a repetition operator allows zero repetitions
+of it, then the back reference makes the whole match fail. For example,
+@samp{(one()|two())-and-(three\2|four\3)} matches @samp{one-and-three}
+and @samp{two-and-four}, but not @samp{one-and-four} or
+@samp{two-and-three}. For example, if the pattern matches
+@samp{one-and-}, then its @w{group 2} matches the empty string and its
+@w{group 3} doesn't participate in the match. So, if it then matches
+@samp{four}, then when it tries to back reference @w{group 3}---which it
+will attempt to do because @samp{\3} follows the @samp{four}---the match
+will fail because @w{group 3} didn't participate in the match.
+
+@end itemize
+
+You can use a back reference as an argument to a repetition operator. For
+example, @samp{(a(b))\2*} matches @samp{a} followed by two or more
+@samp{b}s. Similarly, @samp{(a(b))\2@{3@}} matches @samp{abbbb}.
+
+If there is no preceding @w{@var{digit}-th} subexpression, the regular
+expression is invalid.
+
+
+@node Anchoring Operators, , Back-reference Operator, Common Operators
+@section Anchoring Operators
+
+@cindex anchoring
+@cindex regexp anchoring
+
+These operators can constrain a pattern to match only at the beginning or
+end of the entire string or at the beginning or end of a line.
+
+@menu
+* Match-beginning-of-line Operator:: ^
+* Match-end-of-line Operator:: $
+@end menu
+
+
+@node Match-beginning-of-line Operator, Match-end-of-line Operator, , Anchoring Operators
+@subsection The Match-beginning-of-line Operator (@code{^})
+
+@kindex ^
+@cindex beginning-of-line operator
+@cindex anchors
+
+This operator can match the empty string either at the beginning of the
+string or after a newline character. Thus, it is said to @dfn{anchor}
+the pattern to the beginning of a line.
+
+In the cases following, @samp{^} represents this operator. (Otherwise,
+@samp{^} is ordinary.)
+
+@itemize @bullet
+
+@item
+It (the @samp{^}) is first in the pattern, as in @samp{^foo}.
+
+@cnindex RE_CONTEXT_INDEP_ANCHORS @r{(and @samp{^})}
+@item
+The syntax bit @code{RE_CONTEXT_INDEP_ANCHORS} is set, and it is outside
+a bracket expression.
+
+@cindex open-group operator and @samp{^}
+@cindex alternation operator and @samp{^}
+@item
+It follows an open-group or alternation operator, as in @samp{a\(^b\)}
+and @samp{a\|^b}. @xref{Grouping Operators}, and @ref{Alternation
+Operator}.
+
+@end itemize
+
+These rules imply that some valid patterns containing @samp{^} cannot be
+matched; for example, @samp{foo^bar} if @code{RE_CONTEXT_INDEP_ANCHORS}
+is set.
+
+@vindex not_bol @r{field in pattern buffer}
+If the @code{not_bol} field is set in the pattern buffer (@pxref{GNU
+Pattern Buffers}), then @samp{^} fails to match at the beginning of the
+string. @xref{POSIX Matching}, for when you might find this useful.
+
+@vindex newline_anchor @r{field in pattern buffer}
+If the @code{newline_anchor} field is set in the pattern buffer, then
+@samp{^} fails to match after a newline. This is useful when you do not
+regard the string to be matched as broken into lines.
+
+
+@node Match-end-of-line Operator, , Match-beginning-of-line Operator, Anchoring Operators
+@subsection The Match-end-of-line Operator (@code{$})
+
+@kindex $
+@cindex end-of-line operator
+@cindex anchors
+
+This operator can match the empty string either at the end of
+the string or before a newline character in the string. Thus, it is
+said to @dfn{anchor} the pattern to the end of a line.
+
+It is always represented by @samp{$}. For example, @samp{foo$} usually
+matches, e.g., @samp{foo} and, e.g., the first three characters of
+@samp{foo\nbar}.
+
+Its interaction with the syntax bits and pattern buffer fields is
+exactly the dual of @samp{^}'s; see the previous section. (That is,
+``beginning'' becomes ``end'', ``next'' becomes ``previous'', and
+``after'' becomes ``before''.)
+
+
+@node GNU Operators, GNU Emacs Operators, Common Operators, Top
+@chapter GNU Operators
+
+Following are operators that @sc{gnu} defines (and @sc{posix} doesn't).
+
+@menu
+* Word Operators::
+* Buffer Operators::
+@end menu
+
+@node Word Operators, Buffer Operators, , GNU Operators
+@section Word Operators
+
+The operators in this section require Regex to recognize parts of words.
+Regex uses a syntax table to determine whether or not a character is
+part of a word, i.e., whether or not it is @dfn{word-constituent}.
+
+@menu
+* Non-Emacs Syntax Tables::
+* Match-word-boundary Operator:: \b
+* Match-within-word Operator:: \B
+* Match-beginning-of-word Operator:: \<
+* Match-end-of-word Operator:: \>
+* Match-word-constituent Operator:: \w
+* Match-non-word-constituent Operator:: \W
+@end menu
+
+@node Non-Emacs Syntax Tables, Match-word-boundary Operator, , Word Operators
+@subsection Non-Emacs Syntax Tables
+
+A @dfn{syntax table} is an array indexed by the characters in your
+character set. In the @sc{ascii} encoding, therefore, a syntax table
+has 256 elements. Regex always uses a @code{char *} variable
+@code{re_syntax_table} as its syntax table. In some cases, it
+initializes this variable and in others it expects you to initialize it.
+
+@itemize @bullet
+@item
+If Regex is compiled with the preprocessor symbols @code{emacs} and
+@code{SYNTAX_TABLE} both undefined, then Regex allocates
+@code{re_syntax_table} and initializes an element @var{i} either to
+@code{Sword} (which it defines) if @var{i} is a letter, number, or
+@samp{_}, or to zero if it's not.
+
+@item
+If Regex is compiled with @code{emacs} undefined but @code{SYNTAX_TABLE}
+defined, then Regex expects you to define a @code{char *} variable
+@code{re_syntax_table} to be a valid syntax table.
+
+@item
+@xref{Emacs Syntax Tables}, for what happens when Regex is compiled with
+the preprocessor symbol @code{emacs} defined.
+
+@end itemize
+
+@node Match-word-boundary Operator, Match-within-word Operator, Non-Emacs Syntax Tables, Word Operators
+@subsection The Match-word-boundary Operator (@code{\b})
+
+@cindex @samp{\b}
+@cindex word boundaries, matching
+
+This operator (represented by @samp{\b}) matches the empty string at
+either the beginning or the end of a word. For example, @samp{\brat\b}
+matches the separate word @samp{rat}.
+
+@node Match-within-word Operator, Match-beginning-of-word Operator, Match-word-boundary Operator, Word Operators
+@subsection The Match-within-word Operator (@code{\B})
+
+@cindex @samp{\B}
+
+This operator (represented by @samp{\B}) matches the empty string within
+a word. For example, @samp{c\Brat\Be} matches @samp{crate}, but
+@samp{dirty \Brat} doesn't match @samp{dirty rat}.
+
+@node Match-beginning-of-word Operator, Match-end-of-word Operator, Match-within-word Operator, Word Operators
+@subsection The Match-beginning-of-word Operator (@code{\<})
+
+@cindex @samp{\<}
+
+This operator (represented by @samp{\<}) matches the empty string at the
+beginning of a word.
+
+@node Match-end-of-word Operator, Match-word-constituent Operator, Match-beginning-of-word Operator, Word Operators
+@subsection The Match-end-of-word Operator (@code{\>})
+
+@cindex @samp{\>}
+
+This operator (represented by @samp{\>}) matches the empty string at the
+end of a word.
+
+@node Match-word-constituent Operator, Match-non-word-constituent Operator, Match-end-of-word Operator, Word Operators
+@subsection The Match-word-constituent Operator (@code{\w})
+
+@cindex @samp{\w}
+
+This operator (represented by @samp{\w}) matches any word-constituent
+character.
+
+@node Match-non-word-constituent Operator, , Match-word-constituent Operator, Word Operators
+@subsection The Match-non-word-constituent Operator (@code{\W})
+
+@cindex @samp{\W}
+
+This operator (represented by @samp{\W}) matches any character that is
+not word-constituent.
+
+
+@node Buffer Operators, , Word Operators, GNU Operators
+@section Buffer Operators
+
+Following are operators which work on buffers. In Emacs, a @dfn{buffer}
+is, naturally, an Emacs buffer. For other programs, Regex considers the
+entire string to be matched as the buffer.
+
+@menu
+* Match-beginning-of-buffer Operator:: \`
+* Match-end-of-buffer Operator:: \'
+@end menu
+
+
+@node Match-beginning-of-buffer Operator, Match-end-of-buffer Operator, , Buffer Operators
+@subsection The Match-beginning-of-buffer Operator (@code{\`})
+
+@cindex @samp{\`}
+
+This operator (represented by @samp{\`}) matches the empty string at the
+beginning of the buffer.
+
+@node Match-end-of-buffer Operator, , Match-beginning-of-buffer Operator, Buffer Operators
+@subsection The Match-end-of-buffer Operator (@code{\'})
+
+@cindex @samp{\'}
+
+This operator (represented by @samp{\'}) matches the empty string at the
+end of the buffer.
+
+
+@node GNU Emacs Operators, What Gets Matched?, GNU Operators, Top
+@chapter GNU Emacs Operators
+
+Following are operators that @sc{gnu} defines (and @sc{posix} doesn't)
+that you can use only when Regex is compiled with the preprocessor
+symbol @code{emacs} defined.
+
+@menu
+* Syntactic Class Operators::
+@end menu
+
+
+@node Syntactic Class Operators, , , GNU Emacs Operators
+@section Syntactic Class Operators
+
+The operators in this section require Regex to recognize the syntactic
+classes of characters. Regex uses a syntax table to determine this.
+
+@menu
+* Emacs Syntax Tables::
+* Match-syntactic-class Operator:: \sCLASS
+* Match-not-syntactic-class Operator:: \SCLASS
+@end menu
+
+@node Emacs Syntax Tables, Match-syntactic-class Operator, , Syntactic Class Operators
+@subsection Emacs Syntax Tables
+
+A @dfn{syntax table} is an array indexed by the characters in your
+character set. In the @sc{ascii} encoding, therefore, a syntax table
+has 256 elements.
+
+If Regex is compiled with the preprocessor symbol @code{emacs} defined,
+then Regex expects you to define and initialize the variable
+@code{re_syntax_table} to be an Emacs syntax table. Emacs' syntax
+tables are more complicated than Regex's own (@pxref{Non-Emacs Syntax
+Tables}). @xref{Syntax, , Syntax, emacs, The GNU Emacs User's Manual},
+for a description of Emacs' syntax tables.
+
+@node Match-syntactic-class Operator, Match-not-syntactic-class Operator, Emacs Syntax Tables, Syntactic Class Operators
+@subsection The Match-syntactic-class Operator (@code{\s}@var{class})
+
+@cindex @samp{\s}
+
+This operator matches any character whose syntactic class is represented
+by a specified character. @samp{\s@var{class}} represents this operator
+where @var{class} is the character representing the syntactic class you
+want. For example, @samp{w} represents the syntactic
+class of word-constituent characters, so @samp{\sw} matches any
+word-constituent character.
+
+@node Match-not-syntactic-class Operator, , Match-syntactic-class Operator, Syntactic Class Operators
+@subsection The Match-not-syntactic-class Operator (@code{\S}@var{class})
+
+@cindex @samp{\S}
+
+This operator is similar to the match-syntactic-class operator except
+that it matches any character whose syntactic class is @emph{not}
+represented by the specified character. @samp{\S@var{class}} represents
+this operator. For example, @samp{w} represents the syntactic class of
+word-constituent characters, so @samp{\Sw} matches any character that is
+not word-constituent.
+
+
+@node What Gets Matched?, Programming with Regex, GNU Emacs Operators, Top
+@chapter What Gets Matched?
+
+Regex usually matches strings according to the ``leftmost longest''
+rule; that is, it chooses the longest of the leftmost matches. This
+does not mean that for a regular expression containing subexpressions
+that it simply chooses the longest match for each subexpression, left to
+right; the overall match must also be the longest possible one.
+
+For example, @samp{(ac*)(c*d[ac]*)\1} matches @samp{acdacaaa}, not
+@samp{acdac}, as it would if it were to choose the longest match for the
+first subexpression.
+
+
+@node Programming with Regex, Copying, What Gets Matched?, Top
+@chapter Programming with Regex
+
+Here we describe how you use the Regex data structures and functions in
+C programs. Regex has three interfaces: one designed for @sc{gnu}, one
+compatible with @sc{posix} and one compatible with Berkeley @sc{unix}.
+
+@menu
+* GNU Regex Functions::
+* POSIX Regex Functions::
+* BSD Regex Functions::
+@end menu
+
+
+@node GNU Regex Functions, POSIX Regex Functions, , Programming with Regex
+@section GNU Regex Functions
+
+If you're writing code that doesn't need to be compatible with either
+@sc{posix} or Berkeley @sc{unix}, you can use these functions. They
+provide more options than the other interfaces.
+
+@menu
+* GNU Pattern Buffers:: The re_pattern_buffer type.
+* GNU Regular Expression Compiling:: re_compile_pattern ()
+* GNU Matching:: re_match ()
+* GNU Searching:: re_search ()
+* Matching/Searching with Split Data:: re_match_2 (), re_search_2 ()
+* Searching with Fastmaps:: re_compile_fastmap ()
+* GNU Translate Tables:: The `translate' field.
+* Using Registers:: The re_registers type and related fns.
+* Freeing GNU Pattern Buffers:: regfree ()
+@end menu
+
+
+@node GNU Pattern Buffers, GNU Regular Expression Compiling, , GNU Regex Functions
+@subsection GNU Pattern Buffers
+
+@cindex pattern buffer, definition of
+@tindex re_pattern_buffer @r{definition}
+@tindex struct re_pattern_buffer @r{definition}
+
+To compile, match, or search for a given regular expression, you must
+supply a pattern buffer. A @dfn{pattern buffer} holds one compiled
+regular expression.@footnote{Regular expressions are also referred to as
+``patterns,'' hence the name ``pattern buffer.''}
+
+You can have several different pattern buffers simultaneously, each
+holding a compiled pattern for a different regular expression.
+
+@file{regex.h} defines the pattern buffer @code{struct} as follows:
+
+@example
+[[[ pattern_buffer ]]]
+@end example
+
+
+@node GNU Regular Expression Compiling, GNU Matching, GNU Pattern Buffers, GNU Regex Functions
+@subsection GNU Regular Expression Compiling
+
+In @sc{gnu}, you can both match and search for a given regular
+expression. To do either, you must first compile it in a pattern buffer
+(@pxref{GNU Pattern Buffers}).
+
+@cindex syntax initialization
+@vindex re_syntax_options @r{initialization}
+Regular expressions match according to the syntax with which they were
+compiled; with @sc{gnu}, you indicate what syntax you want by setting
+the variable @code{re_syntax_options} (declared in @file{regex.h} and
+defined in @file{regex.c}) before calling the compiling function,
+@code{re_compile_pattern} (see below). @xref{Syntax Bits}, and
+@ref{Predefined Syntaxes}.
+
+You can change the value of @code{re_syntax_options} at any time.
+Usually, however, you set its value once and then never change it.
+
+@cindex pattern buffer initialization
+@code{re_compile_pattern} takes a pattern buffer as an argument. You
+must initialize the following fields:
+
+@table @code
+
+@item translate @r{initialization}
+
+@item translate
+@vindex translate @r{initialization}
+Initialize this to point to a translate table if you want one, or to
+zero if you don't. We explain translate tables in @ref{GNU Translate
+Tables}.
+
+@item fastmap
+@vindex fastmap @r{initialization}
+Initialize this to nonzero if you want a fastmap, or to zero if you
+don't.
+
+@item buffer
+@itemx allocated
+@vindex buffer @r{initialization}
+@vindex allocated @r{initialization}
+@findex malloc
+If you want @code{re_compile_pattern} to allocate memory for the
+compiled pattern, set both of these to zero. If you have an existing
+block of memory (allocated with @code{malloc}) you want Regex to use,
+set @code{buffer} to its address and @code{allocated} to its size (in
+bytes).
+
+@code{re_compile_pattern} uses @code{realloc} to extend the space for
+the compiled pattern as necessary.
+
+@end table
+
+To compile a pattern buffer, use:
+
+@findex re_compile_pattern
+@example
+char *
+re_compile_pattern (const char *@var{regex}, const int @var{regex_size},
+ struct re_pattern_buffer *@var{pattern_buffer})
+@end example
+
+@noindent
+@var{regex} is the regular expression's address, @var{regex_size} is its
+length, and @var{pattern_buffer} is the pattern buffer's address.
+
+If @code{re_compile_pattern} successfully compiles the regular
+expression, it returns zero and sets @code{*@var{pattern_buffer}} to the
+compiled pattern. It sets the pattern buffer's fields as follows:
+
+@table @code
+@item buffer
+@vindex buffer @r{field, set by @code{re_compile_pattern}}
+to the compiled pattern.
+
+@item used
+@vindex used @r{field, set by @code{re_compile_pattern}}
+to the number of bytes the compiled pattern in @code{buffer} occupies.
+
+@item syntax
+@vindex syntax @r{field, set by @code{re_compile_pattern}}
+to the current value of @code{re_syntax_options}.
+
+@item re_nsub
+@vindex re_nsub @r{field, set by @code{re_compile_pattern}}
+to the number of subexpressions in @var{regex}.
+
+@item fastmap_accurate
+@vindex fastmap_accurate @r{field, set by @code{re_compile_pattern}}
+to zero on the theory that the pattern you're compiling is different
+than the one previously compiled into @code{buffer}; in that case (since
+you can't make a fastmap without a compiled pattern),
+@code{fastmap} would either contain an incompatible fastmap, or nothing
+at all.
+
+@c xx what else?
+@end table
+
+If @code{re_compile_pattern} can't compile @var{regex}, it returns an
+error string corresponding to one of the errors listed in @ref{POSIX
+Regular Expression Compiling}.
+
+
+@node GNU Matching, GNU Searching, GNU Regular Expression Compiling, GNU Regex Functions
+@subsection GNU Matching
+
+@cindex matching with GNU functions
+
+Matching the @sc{gnu} way means trying to match as much of a string as
+possible starting at a position within it you specify. Once you've compiled
+a pattern into a pattern buffer (@pxref{GNU Regular Expression
+Compiling}), you can ask the matcher to match that pattern against a
+string using:
+
+@findex re_match
+@example
+int
+re_match (struct re_pattern_buffer *@var{pattern_buffer},
+ const char *@var{string}, const int @var{size},
+ const int @var{start}, struct re_registers *@var{regs})
+@end example
+
+@noindent
+@var{pattern_buffer} is the address of a pattern buffer containing a
+compiled pattern. @var{string} is the string you want to match; it can
+contain newline and null characters. @var{size} is the length of that
+string. @var{start} is the string index at which you want to
+begin matching; the first character of @var{string} is at index zero.
+@xref{Using Registers}, for a explanation of @var{regs}; you can safely
+pass zero.
+
+@code{re_match} matches the regular expression in @var{pattern_buffer}
+against the string @var{string} according to the syntax in
+@var{pattern_buffers}'s @code{syntax} field. (@xref{GNU Regular
+Expression Compiling}, for how to set it.) The function returns
+@math{-1} if the compiled pattern does not match any part of
+@var{string} and @math{-2} if an internal error happens; otherwise, it
+returns how many (possibly zero) characters of @var{string} the pattern
+matched.
+
+An example: suppose @var{pattern_buffer} points to a pattern buffer
+containing the compiled pattern for @samp{a*}, and @var{string} points
+to @samp{aaaaab} (whereupon @var{size} should be 6). Then if @var{start}
+is 2, @code{re_match} returns 3, i.e., @samp{a*} would have matched the
+last three @samp{a}s in @var{string}. If @var{start} is 0,
+@code{re_match} returns 5, i.e., @samp{a*} would have matched all the
+@samp{a}s in @var{string}. If @var{start} is either 5 or 6, it returns
+zero.
+
+If @var{start} is not between zero and @var{size}, then
+@code{re_match} returns @math{-1}.
+
+
+@node GNU Searching, Matching/Searching with Split Data, GNU Matching, GNU Regex Functions
+@subsection GNU Searching
+
+@cindex searching with GNU functions
+
+@dfn{Searching} means trying to match starting at successive positions
+within a string. The function @code{re_search} does this.
+
+Before calling @code{re_search}, you must compile your regular
+expression. @xref{GNU Regular Expression Compiling}.
+
+Here is the function declaration:
+
+@findex re_search
+@example
+int
+re_search (struct re_pattern_buffer *@var{pattern_buffer},
+ const char *@var{string}, const int @var{size},
+ const int @var{start}, const int @var{range},
+ struct re_registers *@var{regs})
+@end example
+
+@noindent
+@vindex start @r{argument to @code{re_search}}
+@vindex range @r{argument to @code{re_search}}
+whose arguments are the same as those to @code{re_match} (@pxref{GNU
+Matching}) except that the two arguments @var{start} and @var{range}
+replace @code{re_match}'s argument @var{start}.
+
+If @var{range} is positive, then @code{re_search} attempts a match
+starting first at index @var{start}, then at @math{@var{start} + 1} if
+that fails, and so on, up to @math{@var{start} + @var{range}}; if
+@var{range} is negative, then it attempts a match starting first at
+index @var{start}, then at @math{@var{start} -1} if that fails, and so
+on.
+
+If @var{start} is not between zero and @var{size}, then @code{re_search}
+returns @math{-1}. When @var{range} is positive, @code{re_search}
+adjusts @var{range} so that @math{@var{start} + @var{range} - 1} is
+between zero and @var{size}, if necessary; that way it won't search
+outside of @var{string}. Similarly, when @var{range} is negative,
+@code{re_search} adjusts @var{range} so that @math{@var{start} +
+@var{range} + 1} is between zero and @var{size}, if necessary.
+
+If the @code{fastmap} field of @var{pattern_buffer} is zero,
+@code{re_search} matches starting at consecutive positions; otherwise,
+it uses @code{fastmap} to make the search more efficient.
+@xref{Searching with Fastmaps}.
+
+If no match is found, @code{re_search} returns @math{-1}. If
+a match is found, it returns the index where the match began. If an
+internal error happens, it returns @math{-2}.
+
+
+@node Matching/Searching with Split Data, Searching with Fastmaps, GNU Searching, GNU Regex Functions
+@subsection Matching and Searching with Split Data
+
+Using the functions @code{re_match_2} and @code{re_search_2}, you can
+match or search in data that is divided into two strings.
+
+The function:
+
+@findex re_match_2
+@example
+int
+re_match_2 (struct re_pattern_buffer *@var{buffer},
+ const char *@var{string1}, const int @var{size1},
+ const char *@var{string2}, const int @var{size2},
+ const int @var{start},
+ struct re_registers *@var{regs},
+ const int @var{stop})
+@end example
+
+@noindent
+is similar to @code{re_match} (@pxref{GNU Matching}) except that you
+pass @emph{two} data strings and sizes, and an index @var{stop} beyond
+which you don't want the matcher to try matching. As with
+@code{re_match}, if it succeeds, @code{re_match_2} returns how many
+characters of @var{string} it matched. Regard @var{string1} and
+@var{string2} as concatenated when you set the arguments @var{start} and
+@var{stop} and use the contents of @var{regs}; @code{re_match_2} never
+returns a value larger than @math{@var{size1} + @var{size2}}.
+
+The function:
+
+@findex re_search_2
+@example
+int
+re_search_2 (struct re_pattern_buffer *@var{buffer},
+ const char *@var{string1}, const int @var{size1},
+ const char *@var{string2}, const int @var{size2},
+ const int @var{start}, const int @var{range},
+ struct re_registers *@var{regs},
+ const int @var{stop})
+@end example
+
+@noindent
+is similarly related to @code{re_search}.
+
+
+@node Searching with Fastmaps, GNU Translate Tables, Matching/Searching with Split Data, GNU Regex Functions
+@subsection Searching with Fastmaps
+
+@cindex fastmaps
+If you're searching through a long string, you should use a fastmap.
+Without one, the searcher tries to match at consecutive positions in the
+string. Generally, most of the characters in the string could not start
+a match. It takes much longer to try matching at a given position in the
+string than it does to check in a table whether or not the character at
+that position could start a match. A @dfn{fastmap} is such a table.
+
+More specifically, a fastmap is an array indexed by the characters in
+your character set. Under the @sc{ascii} encoding, therefore, a fastmap
+has 256 elements. If you want the searcher to use a fastmap with a
+given pattern buffer, you must allocate the array and assign the array's
+address to the pattern buffer's @code{fastmap} field. You either can
+compile the fastmap yourself or have @code{re_search} do it for you;
+when @code{fastmap} is nonzero, it automatically compiles a fastmap the
+first time you search using a particular compiled pattern.
+
+To compile a fastmap yourself, use:
+
+@findex re_compile_fastmap
+@example
+int
+re_compile_fastmap (struct re_pattern_buffer *@var{pattern_buffer})
+@end example
+
+@noindent
+@var{pattern_buffer} is the address of a pattern buffer. If the
+character @var{c} could start a match for the pattern,
+@code{re_compile_fastmap} makes
+@code{@var{pattern_buffer}->fastmap[@var{c}]} nonzero. It returns
+@math{0} if it can compile a fastmap and @math{-2} if there is an
+internal error. For example, if @samp{|} is the alternation operator
+and @var{pattern_buffer} holds the compiled pattern for @samp{a|b}, then
+@code{re_compile_fastmap} sets @code{fastmap['a']} and
+@code{fastmap['b']} (and no others).
+
+@code{re_search} uses a fastmap as it moves along in the string: it
+checks the string's characters until it finds one that's in the fastmap.
+Then it tries matching at that character. If the match fails, it
+repeats the process. So, by using a fastmap, @code{re_search} doesn't
+waste time trying to match at positions in the string that couldn't
+start a match.
+
+If you don't want @code{re_search} to use a fastmap,
+store zero in the @code{fastmap} field of the pattern buffer before
+calling @code{re_search}.
+
+Once you've initialized a pattern buffer's @code{fastmap} field, you
+need never do so again---even if you compile a new pattern in
+it---provided the way the field is set still reflects whether or not you
+want a fastmap. @code{re_search} will still either do nothing if
+@code{fastmap} is null or, if it isn't, compile a new fastmap for the
+new pattern.
+
+@node GNU Translate Tables, Using Registers, Searching with Fastmaps, GNU Regex Functions
+@subsection GNU Translate Tables
+
+If you set the @code{translate} field of a pattern buffer to a translate
+table, then the @sc{gnu} Regex functions to which you've passed that
+pattern buffer use it to apply a simple transformation
+to all the regular expression and string characters at which they look.
+
+A @dfn{translate table} is an array indexed by the characters in your
+character set. Under the @sc{ascii} encoding, therefore, a translate
+table has 256 elements. The array's elements are also characters in
+your character set. When the Regex functions see a character @var{c},
+they use @code{translate[@var{c}]} in its place, with one exception: the
+character after a @samp{\} is not translated. (This ensures that, the
+operators, e.g., @samp{\B} and @samp{\b}, are always distinguishable.)
+
+For example, a table that maps all lowercase letters to the
+corresponding uppercase ones would cause the matcher to ignore
+differences in case.@footnote{A table that maps all uppercase letters to
+the corresponding lowercase ones would work just as well for this
+purpose.} Such a table would map all characters except lowercase letters
+to themselves, and lowercase letters to the corresponding uppercase
+ones. Under the @sc{ascii} encoding, here's how you could initialize
+such a table (we'll call it @code{case_fold}):
+
+@example
+for (i = 0; i < 256; i++)
+ case_fold[i] = i;
+for (i = 'a'; i <= 'z'; i++)
+ case_fold[i] = i - ('a' - 'A');
+@end example
+
+You tell Regex to use a translate table on a given pattern buffer by
+assigning that table's address to the @code{translate} field of that
+buffer. If you don't want Regex to do any translation, put zero into
+this field. You'll get weird results if you change the table's contents
+anytime between compiling the pattern buffer, compiling its fastmap, and
+matching or searching with the pattern buffer.
+
+@node Using Registers, Freeing GNU Pattern Buffers, GNU Translate Tables, GNU Regex Functions
+@subsection Using Registers
+
+A group in a regular expression can match a (posssibly empty) substring
+of the string that regular expression as a whole matched. The matcher
+remembers the beginning and end of the substring matched by
+each group.
+
+To find out what they matched, pass a nonzero @var{regs} argument to a
+@sc{gnu} matching or searching function (@pxref{GNU Matching} and
+@ref{GNU Searching}), i.e., the address of a structure of this type, as
+defined in @file{regex.h}:
+
+@c We don't bother to include this directly from regex.h,
+@c since it changes so rarely.
+@example
+@tindex re_registers
+@vindex num_regs @r{in @code{struct re_registers}}
+@vindex start @r{in @code{struct re_registers}}
+@vindex end @r{in @code{struct re_registers}}
+struct re_registers
+@{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+@};
+@end example
+
+Except for (possibly) the @var{num_regs}'th element (see below), the
+@var{i}th element of the @code{start} and @code{end} arrays records
+information about the @var{i}th group in the pattern. (They're declared
+as C pointers, but this is only because not all C compilers accept
+zero-length arrays; conceptually, it is simplest to think of them as
+arrays.)
+
+The @code{start} and @code{end} arrays are allocated in various ways,
+depending on the value of the @code{regs_allocated}
+@vindex regs_allocated
+field in the pattern buffer passed to the matcher.
+
+The simplest and perhaps most useful is to let the matcher (re)allocate
+enough space to record information for all the groups in the regular
+expression. If @code{regs_allocated} is @code{REGS_UNALLOCATED},
+@vindex REGS_UNALLOCATED
+the matcher allocates @math{1 + @var{re_nsub}} (another field in the
+pattern buffer; @pxref{GNU Pattern Buffers}). The extra element is set
+to @math{-1}, and sets @code{regs_allocated} to @code{REGS_REALLOCATE}.
+@vindex REGS_REALLOCATE
+Then on subsequent calls with the same pattern buffer and @var{regs}
+arguments, the matcher reallocates more space if necessary.
+
+It would perhaps be more logical to make the @code{regs_allocated} field
+part of the @code{re_registers} structure, instead of part of the
+pattern buffer. But in that case the caller would be forced to
+initialize the structure before passing it. Much existing code doesn't
+do this initialization, and it's arguably better to avoid it anyway.
+
+@code{re_compile_pattern} sets @code{regs_allocated} to
+@code{REGS_UNALLOCATED},
+so if you use the GNU regular expression
+functions, you get this behavior by default.
+
+xx document re_set_registers
+
+@sc{posix}, on the other hand, requires a different interface: the
+caller is supposed to pass in a fixed-length array which the matcher
+fills. Therefore, if @code{regs_allocated} is @code{REGS_FIXED}
+@vindex REGS_FIXED
+the matcher simply fills that array.
+
+The following examples illustrate the information recorded in the
+@code{re_registers} structure. (In all of them, @samp{(} represents the
+open-group and @samp{)} the close-group operator. The first character
+in the string @var{string} is at index 0.)
+
+@c xx i'm not sure this is all true anymore.
+
+@itemize @bullet
+
+@item
+If the regular expression has an @w{@var{i}-th}
+group not contained within another group that matches a
+substring of @var{string}, then the function sets
+@code{@w{@var{regs}->}start[@var{i}]} to the index in @var{string} where
+the substring matched by the @w{@var{i}-th} group begins, and
+@code{@w{@var{regs}->}end[@var{i}]} to the index just beyond that
+substring's end. The function sets @code{@w{@var{regs}->}start[0]} and
+@code{@w{@var{regs}->}end[0]} to analogous information about the entire
+pattern.
+
+For example, when you match @samp{((a)(b))} against @samp{ab}, you get:
+
+@itemize @bullet
+@item
+0 in @code{@w{@var{regs}->}start[0]} and 2 in @code{@w{@var{regs}->}end[0]}
+
+@item
+0 in @code{@w{@var{regs}->}start[1]} and 2 in @code{@w{@var{regs}->}end[1]}
+
+@item
+0 in @code{@w{@var{regs}->}start[2]} and 1 in @code{@w{@var{regs}->}end[2]}
+
+@item
+1 in @code{@w{@var{regs}->}start[3]} and 2 in @code{@w{@var{regs}->}end[3]}
+@end itemize
+
+@item
+If a group matches more than once (as it might if followed by,
+e.g., a repetition operator), then the function reports the information
+about what the group @emph{last} matched.
+
+For example, when you match the pattern @samp{(a)*} against the string
+@samp{aa}, you get:
+
+@itemize @bullet
+@item
+0 in @code{@w{@var{regs}->}start[0]} and 2 in @code{@w{@var{regs}->}end[0]}
+
+@item
+1 in @code{@w{@var{regs}->}start[1]} and 2 in @code{@w{@var{regs}->}end[1]}
+@end itemize
+
+@item
+If the @w{@var{i}-th} group does not participate in a
+successful match, e.g., it is an alternative not taken or a
+repetition operator allows zero repetitions of it, then the function
+sets @code{@w{@var{regs}->}start[@var{i}]} and
+@code{@w{@var{regs}->}end[@var{i}]} to @math{-1}.
+
+For example, when you match the pattern @samp{(a)*b} against
+the string @samp{b}, you get:
+
+@itemize @bullet
+@item
+0 in @code{@w{@var{regs}->}start[0]} and 1 in @code{@w{@var{regs}->}end[0]}
+
+@item
+@math{-1} in @code{@w{@var{regs}->}start[1]} and @math{-1} in @code{@w{@var{regs}->}end[1]}
+@end itemize
+
+@item
+If the @w{@var{i}-th} group matches a zero-length string, then the
+function sets @code{@w{@var{regs}->}start[@var{i}]} and
+@code{@w{@var{regs}->}end[@var{i}]} to the index just beyond that
+zero-length string.
+
+For example, when you match the pattern @samp{(a*)b} against the string
+@samp{b}, you get:
+
+@itemize @bullet
+@item
+0 in @code{@w{@var{regs}->}start[0]} and 1 in @code{@w{@var{regs}->}end[0]}
+
+@item
+0 in @code{@w{@var{regs}->}start[1]} and 0 in @code{@w{@var{regs}->}end[1]}
+@end itemize
+
+@ignore
+The function sets @code{@w{@var{regs}->}start[0]} and
+@code{@w{@var{regs}->}end[0]} to analogous information about the entire
+pattern.
+
+For example, when you match the pattern @samp{(a*)} against the empty
+string, you get:
+
+@itemize @bullet
+@item
+0 in @code{@w{@var{regs}->}start[0]} and 0 in @code{@w{@var{regs}->}end[0]}
+
+@item
+0 in @code{@w{@var{regs}->}start[1]} and 0 in @code{@w{@var{regs}->}end[1]}
+@end itemize
+@end ignore
+
+@item
+If an @w{@var{i}-th} group contains a @w{@var{j}-th} group
+in turn not contained within any other group within group @var{i} and
+the function reports a match of the @w{@var{i}-th} group, then it
+records in @code{@w{@var{regs}->}start[@var{j}]} and
+@code{@w{@var{regs}->}end[@var{j}]} the last match (if it matched) of
+the @w{@var{j}-th} group.
+
+For example, when you match the pattern @samp{((a*)b)*} against the
+string @samp{abb}, @w{group 2} last matches the empty string, so you
+get what it previously matched:
+
+@itemize @bullet
+@item
+0 in @code{@w{@var{regs}->}start[0]} and 3 in @code{@w{@var{regs}->}end[0]}
+
+@item
+2 in @code{@w{@var{regs}->}start[1]} and 3 in @code{@w{@var{regs}->}end[1]}
+
+@item
+2 in @code{@w{@var{regs}->}start[2]} and 2 in @code{@w{@var{regs}->}end[2]}
+@end itemize
+
+When you match the pattern @samp{((a)*b)*} against the string
+@samp{abb}, @w{group 2} doesn't participate in the last match, so you
+get:
+
+@itemize @bullet
+@item
+0 in @code{@w{@var{regs}->}start[0]} and 3 in @code{@w{@var{regs}->}end[0]}
+
+@item
+2 in @code{@w{@var{regs}->}start[1]} and 3 in @code{@w{@var{regs}->}end[1]}
+
+@item
+0 in @code{@w{@var{regs}->}start[2]} and 1 in @code{@w{@var{regs}->}end[2]}
+@end itemize
+
+@item
+If an @w{@var{i}-th} group contains a @w{@var{j}-th} group
+in turn not contained within any other group within group @var{i}
+and the function sets
+@code{@w{@var{regs}->}start[@var{i}]} and
+@code{@w{@var{regs}->}end[@var{i}]} to @math{-1}, then it also sets
+@code{@w{@var{regs}->}start[@var{j}]} and
+@code{@w{@var{regs}->}end[@var{j}]} to @math{-1}.
+
+For example, when you match the pattern @samp{((a)*b)*c} against the
+string @samp{c}, you get:
+
+@itemize @bullet
+@item
+0 in @code{@w{@var{regs}->}start[0]} and 1 in @code{@w{@var{regs}->}end[0]}
+
+@item
+@math{-1} in @code{@w{@var{regs}->}start[1]} and @math{-1} in @code{@w{@var{regs}->}end[1]}
+
+@item
+@math{-1} in @code{@w{@var{regs}->}start[2]} and @math{-1} in @code{@w{@var{regs}->}end[2]}
+@end itemize
+
+@end itemize
+
+@node Freeing GNU Pattern Buffers, , Using Registers, GNU Regex Functions
+@subsection Freeing GNU Pattern Buffers
+
+To free any allocated fields of a pattern buffer, you can use the
+@sc{posix} function described in @ref{Freeing POSIX Pattern Buffers},
+since the type @code{regex_t}---the type for @sc{posix} pattern
+buffers---is equivalent to the type @code{re_pattern_buffer}. After
+freeing a pattern buffer, you need to again compile a regular expression
+in it (@pxref{GNU Regular Expression Compiling}) before passing it to
+a matching or searching function.
+
+
+@node POSIX Regex Functions, BSD Regex Functions, GNU Regex Functions, Programming with Regex
+@section POSIX Regex Functions
+
+If you're writing code that has to be @sc{posix} compatible, you'll need
+to use these functions. Their interfaces are as specified by @sc{posix},
+draft 1003.2/D11.2.
+
+@menu
+* POSIX Pattern Buffers:: The regex_t type.
+* POSIX Regular Expression Compiling:: regcomp ()
+* POSIX Matching:: regexec ()
+* Reporting Errors:: regerror ()
+* Using Byte Offsets:: The regmatch_t type.
+* Freeing POSIX Pattern Buffers:: regfree ()
+@end menu
+
+
+@node POSIX Pattern Buffers, POSIX Regular Expression Compiling, , POSIX Regex Functions
+@subsection POSIX Pattern Buffers
+
+To compile or match a given regular expression the @sc{posix} way, you
+must supply a pattern buffer exactly the way you do for @sc{gnu}
+(@pxref{GNU Pattern Buffers}). @sc{posix} pattern buffers have type
+@code{regex_t}, which is equivalent to the @sc{gnu} pattern buffer
+type @code{re_pattern_buffer}.
+
+
+@node POSIX Regular Expression Compiling, POSIX Matching, POSIX Pattern Buffers, POSIX Regex Functions
+@subsection POSIX Regular Expression Compiling
+
+With @sc{posix}, you can only search for a given regular expression; you
+can't match it. To do this, you must first compile it in a
+pattern buffer, using @code{regcomp}.
+
+@ignore
+Before calling @code{regcomp}, you must initialize this pattern buffer
+as you do for @sc{gnu} (@pxref{GNU Regular Expression Compiling}). See
+below, however, for how to choose a syntax with which to compile.
+@end ignore
+
+To compile a pattern buffer, use:
+
+@findex regcomp
+@example
+int
+regcomp (regex_t *@var{preg}, const char *@var{regex}, int @var{cflags})
+@end example
+
+@noindent
+@var{preg} is the initialized pattern buffer's address, @var{regex} is
+the regular expression's address, and @var{cflags} is the compilation
+flags, which Regex considers as a collection of bits. Here are the
+valid bits, as defined in @file{regex.h}:
+
+@table @code
+
+@item REG_EXTENDED
+@vindex REG_EXTENDED
+says to use @sc{posix} Extended Regular Expression syntax; if this isn't
+set, then says to use @sc{posix} Basic Regular Expression syntax.
+@code{regcomp} sets @var{preg}'s @code{syntax} field accordingly.
+
+@item REG_ICASE
+@vindex REG_ICASE
+@cindex ignoring case
+says to ignore case; @code{regcomp} sets @var{preg}'s @code{translate}
+field to a translate table which ignores case, replacing anything you've
+put there before.
+
+@item REG_NOSUB
+@vindex REG_NOSUB
+says to set @var{preg}'s @code{no_sub} field; @pxref{POSIX Matching},
+for what this means.
+
+@item REG_NEWLINE
+@vindex REG_NEWLINE
+says that a:
+
+@itemize @bullet
+
+@item
+match-any-character operator (@pxref{Match-any-character
+Operator}) doesn't match a newline.
+
+@item
+nonmatching list not containing a newline (@pxref{List
+Operators}) matches a newline.
+
+@item
+match-beginning-of-line operator (@pxref{Match-beginning-of-line
+Operator}) matches the empty string immediately after a newline,
+regardless of how @code{REG_NOTBOL} is set (@pxref{POSIX Matching}, for
+an explanation of @code{REG_NOTBOL}).
+
+@item
+match-end-of-line operator (@pxref{Match-beginning-of-line
+Operator}) matches the empty string immediately before a newline,
+regardless of how @code{REG_NOTEOL} is set (@pxref{POSIX Matching},
+for an explanation of @code{REG_NOTEOL}).
+
+@end itemize
+
+@end table
+
+If @code{regcomp} successfully compiles the regular expression, it
+returns zero and sets @code{*@var{pattern_buffer}} to the compiled
+pattern. Except for @code{syntax} (which it sets as explained above), it
+also sets the same fields the same way as does the @sc{gnu} compiling
+function (@pxref{GNU Regular Expression Compiling}).
+
+If @code{regcomp} can't compile the regular expression, it returns one
+of the error codes listed here. (Except when noted differently, the
+syntax of in all examples below is basic regular expression syntax.)
+
+@table @code
+
+@comment repetitions
+@item REG_BADRPT
+For example, the consecutive repetition operators @samp{**} in
+@samp{a**} are invalid. As another example, if the syntax is extended
+regular expression syntax, then the repetition operator @samp{*} with
+nothing on which to operate in @samp{*} is invalid.
+
+@item REG_BADBR
+For example, the @var{count} @samp{-1} in @samp{a\@{-1} is invalid.
+
+@item REG_EBRACE
+For example, @samp{a\@{1} is missing a close-interval operator.
+
+@comment lists
+@item REG_EBRACK
+For example, @samp{[a} is missing a close-list operator.
+
+@item REG_ERANGE
+For example, the range ending point @samp{z} that collates lower than
+does its starting point @samp{a} in @samp{[z-a]} is invalid. Also, the
+range with the character class @samp{[:alpha:]} as its starting point in
+@samp{[[:alpha:]-|]}.
+
+@item REG_ECTYPE
+For example, the character class name @samp{foo} in @samp{[[:foo:]} is
+invalid.
+
+@comment groups
+@item REG_EPAREN
+For example, @samp{a\)} is missing an open-group operator and @samp{\(a}
+is missing a close-group operator.
+
+@item REG_ESUBREG
+For example, the back reference @samp{\2} that refers to a nonexistent
+subexpression in @samp{\(a\)\2} is invalid.
+
+@comment unfinished business
+
+@item REG_EEND
+Returned when a regular expression causes no other more specific error.
+
+@item REG_EESCAPE
+For example, the trailing backslash @samp{\} in @samp{a\} is invalid, as is the
+one in @samp{\}.
+
+@comment kitchen sink
+@item REG_BADPAT
+For example, in the extended regular expression syntax, the empty group
+@samp{()} in @samp{a()b} is invalid.
+
+@comment internal
+@item REG_ESIZE
+Returned when a regular expression needs a pattern buffer larger than
+65536 bytes.
+
+@item REG_ESPACE
+Returned when a regular expression makes Regex to run out of memory.
+
+@end table
+
+
+@node POSIX Matching, Reporting Errors, POSIX Regular Expression Compiling, POSIX Regex Functions
+@subsection POSIX Matching
+
+Matching the @sc{posix} way means trying to match a null-terminated
+string starting at its first character. Once you've compiled a pattern
+into a pattern buffer (@pxref{POSIX Regular Expression Compiling}), you
+can ask the matcher to match that pattern against a string using:
+
+@findex regexec
+@example
+int
+regexec (const regex_t *@var{preg}, const char *@var{string},
+ size_t @var{nmatch}, regmatch_t @var{pmatch}[], int @var{eflags})
+@end example
+
+@noindent
+@var{preg} is the address of a pattern buffer for a compiled pattern.
+@var{string} is the string you want to match.
+
+@xref{Using Byte Offsets}, for an explanation of @var{pmatch}. If you
+pass zero for @var{nmatch} or you compiled @var{preg} with the
+compilation flag @code{REG_NOSUB} set, then @code{regexec} will ignore
+@var{pmatch}; otherwise, you must allocate it to have at least
+@var{nmatch} elements. @code{regexec} will record @var{nmatch} byte
+offsets in @var{pmatch}, and set to @math{-1} any unused elements up to
+@math{@var{pmatch}@code{[@var{nmatch}]} - 1}.
+
+@var{eflags} specifies @dfn{execution flags}---namely, the two bits
+@code{REG_NOTBOL} and @code{REG_NOTEOL} (defined in @file{regex.h}). If
+you set @code{REG_NOTBOL}, then the match-beginning-of-line operator
+(@pxref{Match-beginning-of-line Operator}) always fails to match.
+This lets you match against pieces of a line, as you would need to if,
+say, searching for repeated instances of a given pattern in a line; it
+would work correctly for patterns both with and without
+match-beginning-of-line operators. @code{REG_NOTEOL} works analogously
+for the match-end-of-line operator (@pxref{Match-end-of-line
+Operator}); it exists for symmetry.
+
+@code{regexec} tries to find a match for @var{preg} in @var{string}
+according to the syntax in @var{preg}'s @code{syntax} field.
+(@xref{POSIX Regular Expression Compiling}, for how to set it.) The
+function returns zero if the compiled pattern matches @var{string} and
+@code{REG_NOMATCH} (defined in @file{regex.h}) if it doesn't.
+
+@node Reporting Errors, Using Byte Offsets, POSIX Matching, POSIX Regex Functions
+@subsection Reporting Errors
+
+If either @code{regcomp} or @code{regexec} fail, they return a nonzero
+error code, the possibilities for which are defined in @file{regex.h}.
+@xref{POSIX Regular Expression Compiling}, and @ref{POSIX Matching}, for
+what these codes mean. To get an error string corresponding to these
+codes, you can use:
+
+@findex regerror
+@example
+size_t
+regerror (int @var{errcode},
+ const regex_t *@var{preg},
+ char *@var{errbuf},
+ size_t @var{errbuf_size})
+@end example
+
+@noindent
+@var{errcode} is an error code, @var{preg} is the address of the pattern
+buffer which provoked the error, @var{errbuf} is the error buffer, and
+@var{errbuf_size} is @var{errbuf}'s size.
+
+@code{regerror} returns the size in bytes of the error string
+corresponding to @var{errcode} (including its terminating null). If
+@var{errbuf} and @var{errbuf_size} are nonzero, it also returns in
+@var{errbuf} the first @math{@var{errbuf_size} - 1} characters of the
+error string, followed by a null.
+@var{errbuf_size} must be a nonnegative number less than or equal to the
+size in bytes of @var{errbuf}.
+
+You can call @code{regerror} with a null @var{errbuf} and a zero
+@var{errbuf_size} to determine how large @var{errbuf} need be to
+accommodate @code{regerror}'s error string.
+
+@node Using Byte Offsets, Freeing POSIX Pattern Buffers, Reporting Errors, POSIX Regex Functions
+@subsection Using Byte Offsets
+
+In @sc{posix}, variables of type @code{regmatch_t} hold analogous
+information, but are not identical to, @sc{gnu}'s registers (@pxref{Using
+Registers}). To get information about registers in @sc{posix}, pass to
+@code{regexec} a nonzero @var{pmatch} of type @code{regmatch_t}, i.e.,
+the address of a structure of this type, defined in
+@file{regex.h}:
+
+@tindex regmatch_t
+@example
+typedef struct
+@{
+ regoff_t rm_so;
+ regoff_t rm_eo;
+@} regmatch_t;
+@end example
+
+When reading in @ref{Using Registers}, about how the matching function
+stores the information into the registers, substitute @var{pmatch} for
+@var{regs}, @code{@w{@var{pmatch}[@var{i}]->}rm_so} for
+@code{@w{@var{regs}->}start[@var{i}]} and
+@code{@w{@var{pmatch}[@var{i}]->}rm_eo} for
+@code{@w{@var{regs}->}end[@var{i}]}.
+
+@node Freeing POSIX Pattern Buffers, , Using Byte Offsets, POSIX Regex Functions
+@subsection Freeing POSIX Pattern Buffers
+
+To free any allocated fields of a pattern buffer, use:
+
+@findex regfree
+@example
+void
+regfree (regex_t *@var{preg})
+@end example
+
+@noindent
+@var{preg} is the pattern buffer whose allocated fields you want freed.
+@code{regfree} also sets @var{preg}'s @code{allocated} and @code{used}
+fields to zero. After freeing a pattern buffer, you need to again
+compile a regular expression in it (@pxref{POSIX Regular Expression
+Compiling}) before passing it to the matching function (@pxref{POSIX
+Matching}).
+
+
+@node BSD Regex Functions, , POSIX Regex Functions, Programming with Regex
+@section BSD Regex Functions
+
+If you're writing code that has to be Berkeley @sc{unix} compatible,
+you'll need to use these functions whose interfaces are the same as those
+in Berkeley @sc{unix}.
+
+@menu
+* BSD Regular Expression Compiling:: re_comp ()
+* BSD Searching:: re_exec ()
+@end menu
+
+@node BSD Regular Expression Compiling, BSD Searching, , BSD Regex Functions
+@subsection BSD Regular Expression Compiling
+
+With Berkeley @sc{unix}, you can only search for a given regular
+expression; you can't match one. To search for it, you must first
+compile it. Before you compile it, you must indicate the regular
+expression syntax you want it compiled according to by setting the
+variable @code{re_syntax_options} (declared in @file{regex.h} to some
+syntax (@pxref{Regular Expression Syntax}).
+
+To compile a regular expression use:
+
+@findex re_comp
+@example
+char *
+re_comp (char *@var{regex})
+@end example
+
+@noindent
+@var{regex} is the address of a null-terminated regular expression.
+@code{re_comp} uses an internal pattern buffer, so you can use only the
+most recently compiled pattern buffer. This means that if you want to
+use a given regular expression that you've already compiled---but it
+isn't the latest one you've compiled---you'll have to recompile it. If
+you call @code{re_comp} with the null string (@emph{not} the empty
+string) as the argument, it doesn't change the contents of the pattern
+buffer.
+
+If @code{re_comp} successfully compiles the regular expression, it
+returns zero. If it can't compile the regular expression, it returns
+an error string. @code{re_comp}'s error messages are identical to those
+of @code{re_compile_pattern} (@pxref{GNU Regular Expression
+Compiling}).
+
+@node BSD Searching, , BSD Regular Expression Compiling, BSD Regex Functions
+@subsection BSD Searching
+
+Searching the Berkeley @sc{unix} way means searching in a string
+starting at its first character and trying successive positions within
+it to find a match. Once you've compiled a pattern using @code{re_comp}
+(@pxref{BSD Regular Expression Compiling}), you can ask Regex
+to search for that pattern in a string using:
+
+@findex re_exec
+@example
+int
+re_exec (char *@var{string})
+@end example
+
+@noindent
+@var{string} is the address of the null-terminated string in which you
+want to search.
+
+@code{re_exec} returns either 1 for success or 0 for failure. It
+automatically uses a @sc{gnu} fastmap (@pxref{Searching with Fastmaps}).
+
+
+@node Copying, Index, Programming with Regex, Top
+@appendix GNU GENERAL PUBLIC LICENSE
+@center Version 2, June 1991
+
+@display
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+675 Mass Ave, Cambridge, MA 02139, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@unnumberedsec Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software---to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+@iftex
+@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifinfo
+@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end ifinfo
+
+@enumerate
+@item
+This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The ``Program'', below,
+refers to any such program or work, and a ``work based on the Program''
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term ``modification''.) Each licensee is addressed as ``you''.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+@item
+You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+@item
+You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+@enumerate a
+@item
+You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+@item
+You must cause any work that you distribute or publish, that in
+whole or in part contains or is derived from the Program or any
+part thereof, to be licensed as a whole at no charge to all third
+parties under the terms of this License.
+
+@item
+If the modified program normally reads commands interactively
+when run, you must cause it, when started running for such
+interactive use in the most ordinary way, to print or display an
+announcement including an appropriate copyright notice and a
+notice that there is no warranty (or else, saying that you provide
+a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this
+License. (Exception: if the Program itself is interactive but
+does not normally print such an announcement, your work based on
+the Program is not required to print an announcement.)
+@end enumerate
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+@item
+You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+@enumerate a
+@item
+Accompany it with the complete corresponding machine-readable
+source code, which must be distributed under the terms of Sections
+1 and 2 above on a medium customarily used for software interchange; or,
+
+@item
+Accompany it with a written offer, valid for at least three
+years, to give any third party, for a charge no more than your
+cost of physically performing source distribution, a complete
+machine-readable copy of the corresponding source code, to be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange; or,
+
+@item
+Accompany it with the information you received as to the offer
+to distribute corresponding source code. (This alternative is
+allowed only for noncommercial distribution and only if you
+received the program in object code or executable form with such
+an offer, in accord with Subsection b above.)
+@end enumerate
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+@item
+You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+@item
+You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+@item
+Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+@item
+If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+@item
+If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+@item
+The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and ``any
+later version'', you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+@item
+If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+@iftex
+@heading NO WARRANTY
+@end iftex
+@ifinfo
+@center NO WARRANTY
+@end ifinfo
+
+@item
+BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+@item
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+@end enumerate
+
+@iftex
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center END OF TERMS AND CONDITIONS
+@end ifinfo
+
+@page
+@unnumberedsec Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+
+@smallexample
+@var{one line to give the program's name and a brief idea of what it does.}
+Copyright (C) 19@var{yy} @var{name of author}
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+@end smallexample
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+@smallexample
+Gnomovision version 69, Copyright (C) 19@var{yy} @var{name of author}
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+This is free software, and you are welcome to redistribute it
+under certain conditions; type `show c' for details.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than @samp{show w} and
+@samp{show c}; they could even be mouse-clicks or menu items---whatever
+suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a ``copyright disclaimer'' for the program, if
+necessary. Here is a sample; alter the names:
+
+@example
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end example
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+
+@node Index, , Copying, Top
+@unnumbered Index
+
+@printindex cp
+
+@contents
+
+@bye
diff --git a/gnu/lib/libregex/gnuregex.h b/gnu/lib/libregex/gnuregex.h
new file mode 100644
index 0000000..7356f9f
--- /dev/null
+++ b/gnu/lib/libregex/gnuregex.h
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2004 David E. O'Brien
+ * Copyright (c) 2004 Andrey A. Chernov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifdef __GNUC__
+#warning "Use -I/usr/include/gnu and <regex.h> instead of <gnuregex.h>"
+#endif
+#include <gnu/regex.h>
diff --git a/gnu/lib/libregex/posix/regex.h b/gnu/lib/libregex/posix/regex.h
new file mode 100644
index 0000000..b2d9a62
--- /dev/null
+++ b/gnu/lib/libregex/posix/regex.h
@@ -0,0 +1,593 @@
+/* Definitions for data structures and routines for the regular
+ expression library.
+ Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _REGEX_H
+#define _REGEX_H 1
+
+#include <sys/types.h>
+
+/* Allow the use in C++ code. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
+
+#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+# include <stddef.h>
+#endif
+
+/* The following two types have to be signed and unsigned integer type
+ wide enough to hold a value of a pointer. For most ANSI compilers
+ ptrdiff_t and size_t should be likely OK. Still size of these two
+ types is 2 for Microsoft C. Ugh... */
+typedef long int s_reg_t;
+typedef unsigned long int active_reg_t;
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned long int reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported. They are:
+ [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
+ [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+ If not set, then character classes are not supported. */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+ without further backtracking. */
+#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* If this bit is set, do not process the GNU regex operators.
+ If not set, then the GNU regex operators are recognized. */
+#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
+
+/* If this bit is set, turn on internal regex debugging.
+ If not set, and debugging was on, turn it off.
+ This only works if regex.c is compiled -DDEBUG.
+ We define this bit always, so that all that's needed to turn on
+ debugging is to recompile regex.c; the calling code can always have
+ this bit set, and it won't affect anything in the normal case. */
+#define RE_DEBUG (RE_NO_GNU_OPS << 1)
+
+/* If this bit is set, a syntactically invalid interval is treated as
+ a string of ordinary characters. For example, the ERE 'a{1' is
+ treated as 'a\{1'. */
+#define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1)
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
+
+/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only
+ for ^, because it is difficult to scan the regex backwards to find
+ whether ^ should be special. */
+#define RE_CARET_ANCHORS_HERE (RE_ICASE << 1)
+
+/* If this bit is set, then \{ cannot be first in an bre or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1)
+
+/* If this bit is set, then no_sub will be set to 1 during
+ re_compile_pattern. */
+#define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GNU_AWK \
+ ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \
+ & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS \
+ | RE_CONTEXT_INVALID_OPS ))
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
+ | RE_INTERVALS | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \
+ | RE_INVALID_INTERVAL_ORD)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is
+ removed and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+# undef RE_DUP_MAX
+#endif
+/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */
+#define RE_DUP_MAX (0x7fff)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+/* Use PMATCH[0] to delimit the start and end of the search in the
+ buffer. */
+#define REG_STARTEND (1 << 2)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+#ifdef _XOPEN_SOURCE
+ REG_ENOSYS = -1, /* This will never happen for this implementation. */
+#endif
+
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Inalid collating element. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+#ifndef RE_TRANSLATE_TYPE
+# define RE_TRANSLATE_TYPE char *
+#endif
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are
+ sometimes used as array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long int allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long int used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses
+ the fastmap, if there is one, to skip over impossible
+ starting points for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation
+ is applied to a pattern when it is compiled and to a string
+ when it is matched. */
+ RE_TRANSLATE_TYPE translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see
+ whether or not we should use the fastmap, so we don't set
+ this absolutely perfectly; see `re_compile_fastmap' (the
+ `duplicate' case). */
+ unsigned can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned regs_allocated : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef RE_NREGS
+# define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+
+/* Declarations for routines. */
+
+/* To avoid duplicating every routine declaration -- once with a
+ prototype (if we are ANSI), and once without (if we aren't) -- we
+ use the following macro to declare argument types. This
+ unfortunately clutters up the declarations a bit, but I think it's
+ worth it. */
+
+#if __STDC__
+
+# define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+# define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern
+ _RE_ARGS ((const char *pattern, size_t length,
+ struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, and must each be at least `NUM_REGS * sizeof
+ (regoff_t)' bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+extern void re_set_registers
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+# ifndef _CRAY
+/* 4.2 bsd compatibility. */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+# endif
+#endif
+
+/* GCC 2.95 and later have "__restrict"; C99 compilers have
+ "restrict", and "configure" may have defined "restrict". */
+#ifndef __restrict
+# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__))
+# if defined restrict || 199901L <= __STDC_VERSION__
+# define __restrict restrict
+# else
+# define __restrict
+# endif
+# endif
+#endif
+/* gcc 3.1 and up support the [restrict] syntax. */
+#ifndef __restrict_arr
+# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+# define __restrict_arr __restrict
+# else
+# define __restrict_arr
+# endif
+#endif
+
+/* POSIX compatibility. */
+extern int regcomp _RE_ARGS ((regex_t *__restrict __preg,
+ const char *__restrict __pattern,
+ int __cflags));
+
+extern int regexec _RE_ARGS ((const regex_t *__restrict __preg,
+ const char *__restrict __string, size_t __nmatch,
+ regmatch_t __pmatch[__restrict_arr],
+ int __eflags));
+
+extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg,
+ char *__errbuf, size_t __errbuf_size));
+
+extern void regfree _RE_ARGS ((regex_t *__preg));
+
+
+#ifdef __cplusplus
+}
+#endif /* C++ */
+
+#endif /* regex.h */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/gnu/lib/libregex/regcomp.c b/gnu/lib/libregex/regcomp.c
new file mode 100644
index 0000000..68e2bda
--- /dev/null
+++ b/gnu/lib/libregex/regcomp.c
@@ -0,0 +1,3924 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
+ int length, reg_syntax_t syntax);
+static void re_compile_fastmap_iter (regex_t *bufp,
+ const re_dfastate_t *init_state,
+ char *fastmap);
+static reg_errcode_t init_dfa (re_dfa_t *dfa, int pat_len);
+static void init_word_char (re_dfa_t *dfa);
+#ifdef RE_ENABLE_I18N
+static void free_charset (re_charset_t *cset);
+#endif /* RE_ENABLE_I18N */
+static void free_workarea_compile (regex_t *preg);
+static reg_errcode_t create_initial_state (re_dfa_t *dfa);
+#ifdef RE_ENABLE_I18N
+static void optimize_utf8 (re_dfa_t *dfa);
+#endif
+static reg_errcode_t analyze (regex_t *preg);
+static reg_errcode_t create_initial_state (re_dfa_t *dfa);
+static reg_errcode_t preorder (bin_tree_t *root,
+ reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra);
+static reg_errcode_t postorder (bin_tree_t *root,
+ reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra);
+static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node);
+static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node);
+static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg,
+ bin_tree_t *node);
+static reg_errcode_t calc_first (void *extra, bin_tree_t *node);
+static reg_errcode_t calc_next (void *extra, bin_tree_t *node);
+static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node);
+static reg_errcode_t duplicate_node_closure (re_dfa_t *dfa, int top_org_node,
+ int top_clone_node, int root_node,
+ unsigned int constraint);
+static reg_errcode_t duplicate_node (int *new_idx, re_dfa_t *dfa, int org_idx,
+ unsigned int constraint);
+static int search_duplicated_node (re_dfa_t *dfa, int org_node,
+ unsigned int constraint);
+static reg_errcode_t calc_eclosure (re_dfa_t *dfa);
+static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa,
+ int node, int root);
+static reg_errcode_t calc_inveclosure (re_dfa_t *dfa);
+static int fetch_number (re_string_t *input, re_token_t *token,
+ reg_syntax_t syntax);
+static void fetch_token (re_token_t *result, re_string_t *input,
+ reg_syntax_t syntax);
+static int peek_token (re_token_t *token, re_string_t *input,
+ reg_syntax_t syntax);
+static int peek_token_bracket (re_token_t *token, re_string_t *input,
+ reg_syntax_t syntax);
+static bin_tree_t *parse (re_string_t *regexp, regex_t *preg,
+ reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp,
+ re_dfa_t *dfa, re_token_t *token,
+ reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa,
+ re_token_t *token, reg_syntax_t syntax,
+ reg_errcode_t *err);
+static reg_errcode_t parse_bracket_element (bracket_elem_t *elem,
+ re_string_t *regexp,
+ re_token_t *token, int token_len,
+ re_dfa_t *dfa,
+ reg_syntax_t syntax,
+ int accept_hyphen);
+static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem,
+ re_string_t *regexp,
+ re_token_t *token);
+#ifndef _LIBC
+# ifdef RE_ENABLE_I18N
+static reg_errcode_t build_range_exp (re_bitset_ptr_t sbcset,
+ re_charset_t *mbcset, int *range_alloc,
+ bracket_elem_t *start_elem,
+ bracket_elem_t *end_elem);
+static reg_errcode_t build_collating_symbol (re_bitset_ptr_t sbcset,
+ re_charset_t *mbcset,
+ int *coll_sym_alloc,
+ const unsigned char *name);
+# else /* not RE_ENABLE_I18N */
+static reg_errcode_t build_range_exp (re_bitset_ptr_t sbcset,
+ bracket_elem_t *start_elem,
+ bracket_elem_t *end_elem);
+static reg_errcode_t build_collating_symbol (re_bitset_ptr_t sbcset,
+ const unsigned char *name);
+# endif /* not RE_ENABLE_I18N */
+#endif /* not _LIBC */
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset,
+ re_charset_t *mbcset,
+ int *equiv_class_alloc,
+ const unsigned char *name);
+static reg_errcode_t build_charclass (unsigned RE_TRANSLATE_TYPE trans,
+ re_bitset_ptr_t sbcset,
+ re_charset_t *mbcset,
+ int *char_class_alloc,
+ const unsigned char *class_name,
+ reg_syntax_t syntax);
+#else /* not RE_ENABLE_I18N */
+static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset,
+ const unsigned char *name);
+static reg_errcode_t build_charclass (unsigned RE_TRANSLATE_TYPE trans,
+ re_bitset_ptr_t sbcset,
+ const unsigned char *class_name,
+ reg_syntax_t syntax);
+#endif /* not RE_ENABLE_I18N */
+static bin_tree_t *build_charclass_op (re_dfa_t *dfa,
+ unsigned RE_TRANSLATE_TYPE trans,
+ const unsigned char *class_name,
+ const unsigned char *extra,
+ int non_match, reg_errcode_t *err);
+static bin_tree_t *create_tree (re_dfa_t *dfa,
+ bin_tree_t *left, bin_tree_t *right,
+ re_token_type_t type);
+static bin_tree_t *create_token_tree (re_dfa_t *dfa,
+ bin_tree_t *left, bin_tree_t *right,
+ const re_token_t *token);
+static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa);
+static void free_token (re_token_t *node);
+static reg_errcode_t free_tree (void *extra, bin_tree_t *node);
+static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node);
+
+/* This table gives an error message for each of the error codes listed
+ in regex.h. Obviously the order here has to be same as there.
+ POSIX doesn't require that we do anything for REG_NOERROR,
+ but why not be nice? */
+
+const char __re_error_msgid[] attribute_hidden =
+ {
+#define REG_NOERROR_IDX 0
+ gettext_noop ("Success") /* REG_NOERROR */
+ "\0"
+#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
+ gettext_noop ("No match") /* REG_NOMATCH */
+ "\0"
+#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match")
+ gettext_noop ("Invalid regular expression") /* REG_BADPAT */
+ "\0"
+#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
+ gettext_noop ("Invalid collation character") /* REG_ECOLLATE */
+ "\0"
+#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character")
+ gettext_noop ("Invalid character class name") /* REG_ECTYPE */
+ "\0"
+#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name")
+ gettext_noop ("Trailing backslash") /* REG_EESCAPE */
+ "\0"
+#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash")
+ gettext_noop ("Invalid back reference") /* REG_ESUBREG */
+ "\0"
+#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference")
+ gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */
+ "\0"
+#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^")
+ gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */
+ "\0"
+#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(")
+ gettext_noop ("Unmatched \\{") /* REG_EBRACE */
+ "\0"
+#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{")
+ gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */
+ "\0"
+#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}")
+ gettext_noop ("Invalid range end") /* REG_ERANGE */
+ "\0"
+#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end")
+ gettext_noop ("Memory exhausted") /* REG_ESPACE */
+ "\0"
+#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted")
+ gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */
+ "\0"
+#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression")
+ gettext_noop ("Premature end of regular expression") /* REG_EEND */
+ "\0"
+#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression")
+ gettext_noop ("Regular expression too big") /* REG_ESIZE */
+ "\0"
+#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big")
+ gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
+ };
+
+const size_t __re_error_msgid_idx[] attribute_hidden =
+ {
+ REG_NOERROR_IDX,
+ REG_NOMATCH_IDX,
+ REG_BADPAT_IDX,
+ REG_ECOLLATE_IDX,
+ REG_ECTYPE_IDX,
+ REG_EESCAPE_IDX,
+ REG_ESUBREG_IDX,
+ REG_EBRACK_IDX,
+ REG_EPAREN_IDX,
+ REG_EBRACE_IDX,
+ REG_BADBR_IDX,
+ REG_ERANGE_IDX,
+ REG_ESPACE_IDX,
+ REG_BADRPT_IDX,
+ REG_EEND_IDX,
+ REG_ESIZE_IDX,
+ REG_ERPAREN_IDX
+ };
+
+/* Entry points for GNU code. */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+ compiles PATTERN (of length LENGTH) and puts the result in BUFP.
+ Returns 0 if the pattern was valid, otherwise an error string.
+
+ Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+ are set in BUFP on entry. */
+
+const char *
+re_compile_pattern (pattern, length, bufp)
+ const char *pattern;
+ size_t length;
+ struct re_pattern_buffer *bufp;
+{
+ reg_errcode_t ret;
+
+ /* And GNU code determines whether or not to get register information
+ by passing null for the REGS argument to re_match, etc., not by
+ setting no_sub, unless RE_NO_SUB is set. */
+ bufp->no_sub = !!(re_syntax_options & RE_NO_SUB);
+
+ /* Match anchors at newline. */
+ bufp->newline_anchor = 1;
+
+ ret = re_compile_internal (bufp, pattern, length, re_syntax_options);
+
+ if (!ret)
+ return NULL;
+ return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
+}
+#ifdef _LIBC
+weak_alias (__re_compile_pattern, re_compile_pattern)
+#endif
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
+ also be assigned to arbitrarily: each pattern buffer stores its own
+ syntax, so it can be changed between regex compilations. */
+/* This has no initializer because initialized variables in Emacs
+ become read-only after dumping. */
+reg_syntax_t re_syntax_options;
+
+
+/* Specify the precise syntax of regexps for compilation. This provides
+ for compatibility for various utilities which historically have
+ different, incompatible syntaxes.
+
+ The argument SYNTAX is a bit mask comprised of the various bits
+ defined in regex.h. We return the old syntax. */
+
+reg_syntax_t
+re_set_syntax (syntax)
+ reg_syntax_t syntax;
+{
+ reg_syntax_t ret = re_syntax_options;
+
+ re_syntax_options = syntax;
+ return ret;
+}
+#ifdef _LIBC
+weak_alias (__re_set_syntax, re_set_syntax)
+#endif
+
+int
+re_compile_fastmap (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+ char *fastmap = bufp->fastmap;
+
+ memset (fastmap, '\0', sizeof (char) * SBC_MAX);
+ re_compile_fastmap_iter (bufp, dfa->init_state, fastmap);
+ if (dfa->init_state != dfa->init_state_word)
+ re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap);
+ if (dfa->init_state != dfa->init_state_nl)
+ re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap);
+ if (dfa->init_state != dfa->init_state_begbuf)
+ re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap);
+ bufp->fastmap_accurate = 1;
+ return 0;
+}
+#ifdef _LIBC
+weak_alias (__re_compile_fastmap, re_compile_fastmap)
+#endif
+
+static inline void
+__attribute ((always_inline))
+re_set_fastmap (char *fastmap, int icase, int ch)
+{
+ fastmap[ch] = 1;
+ if (icase)
+ fastmap[tolower (ch)] = 1;
+}
+
+/* Helper function for re_compile_fastmap.
+ Compile fastmap for the initial_state INIT_STATE. */
+
+static void
+re_compile_fastmap_iter (bufp, init_state, fastmap)
+ regex_t *bufp;
+ const re_dfastate_t *init_state;
+ char *fastmap;
+{
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+ int node_cnt;
+ int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE));
+ for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt)
+ {
+ int node = init_state->nodes.elems[node_cnt];
+ re_token_type_t type = dfa->nodes[node].type;
+
+ if (type == CHARACTER)
+ {
+ re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c);
+#ifdef RE_ENABLE_I18N
+ if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
+ {
+ unsigned char *buf = alloca (dfa->mb_cur_max), *p;
+ wchar_t wc;
+ mbstate_t state;
+
+ p = buf;
+ *p++ = dfa->nodes[node].opr.c;
+ while (++node < dfa->nodes_len
+ && dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].mb_partial)
+ *p++ = dfa->nodes[node].opr.c;
+ memset (&state, 0, sizeof (state));
+ if (mbrtowc (&wc, (const char *) buf, p - buf,
+ &state) == p - buf
+ && (__wcrtomb ((char *) buf, towlower (wc), &state)
+ != (size_t) -1))
+ re_set_fastmap (fastmap, 0, buf[0]);
+ }
+#endif
+ }
+ else if (type == SIMPLE_BRACKET)
+ {
+ int i, j, ch;
+ for (i = 0, ch = 0; i < BITSET_UINTS; ++i)
+ for (j = 0; j < UINT_BITS; ++j, ++ch)
+ if (dfa->nodes[node].opr.sbcset[i] & (1 << j))
+ re_set_fastmap (fastmap, icase, ch);
+ }
+#ifdef RE_ENABLE_I18N
+ else if (type == COMPLEX_BRACKET)
+ {
+ int i;
+ re_charset_t *cset = dfa->nodes[node].opr.mbcset;
+ if (cset->non_match || cset->ncoll_syms || cset->nequiv_classes
+ || cset->nranges || cset->nchar_classes)
+ {
+# ifdef _LIBC
+ if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0)
+ {
+ /* In this case we want to catch the bytes which are
+ the first byte of any collation elements.
+ e.g. In da_DK, we want to catch 'a' since "aa"
+ is a valid collation element, and don't catch
+ 'b' since 'b' is the only collation element
+ which starts from 'b'. */
+ int j, ch;
+ const int32_t *table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ for (i = 0, ch = 0; i < BITSET_UINTS; ++i)
+ for (j = 0; j < UINT_BITS; ++j, ++ch)
+ if (table[ch] < 0)
+ re_set_fastmap (fastmap, icase, ch);
+ }
+# else
+ if (dfa->mb_cur_max > 1)
+ for (i = 0; i < SBC_MAX; ++i)
+ if (__btowc (i) == WEOF)
+ re_set_fastmap (fastmap, icase, i);
+# endif /* not _LIBC */
+ }
+ for (i = 0; i < cset->nmbchars; ++i)
+ {
+ char buf[256];
+ mbstate_t state;
+ memset (&state, '\0', sizeof (state));
+ if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1)
+ re_set_fastmap (fastmap, icase, *(unsigned char *) buf);
+ if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
+ {
+ if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state)
+ != (size_t) -1)
+ re_set_fastmap (fastmap, 0, *(unsigned char *) buf);
+ }
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ else if (type == OP_PERIOD
+#ifdef RE_ENABLE_I18N
+ || type == OP_UTF8_PERIOD
+#endif /* RE_ENABLE_I18N */
+ || type == END_OF_RE)
+ {
+ memset (fastmap, '\1', sizeof (char) * SBC_MAX);
+ if (type == END_OF_RE)
+ bufp->can_be_null = 1;
+ return;
+ }
+ }
+}
+
+/* Entry point for POSIX code. */
+/* regcomp takes a regular expression as a string and compiles it.
+
+ PREG is a regex_t *. We do not expect any fields to be initialized,
+ since POSIX says we shouldn't. Thus, we set
+
+ `buffer' to the compiled pattern;
+ `used' to the length of the compiled pattern;
+ `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+ REG_EXTENDED bit in CFLAGS is set; otherwise, to
+ RE_SYNTAX_POSIX_BASIC;
+ `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+ `fastmap' to an allocated space for the fastmap;
+ `fastmap_accurate' to zero;
+ `re_nsub' to the number of subexpressions in PATTERN.
+
+ PATTERN is the address of the pattern string.
+
+ CFLAGS is a series of bits which affect compilation.
+
+ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+ use POSIX basic syntax.
+
+ If REG_NEWLINE is set, then . and [^...] don't match newline.
+ Also, regexec will try a match beginning after every newline.
+
+ If REG_ICASE is set, then we considers upper- and lowercase
+ versions of letters to be equivalent when matching.
+
+ If REG_NOSUB is set, then when PREG is passed to regexec, that
+ routine will report only success or failure, and nothing about the
+ registers.
+
+ It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
+ the return codes and their meanings.) */
+
+int
+regcomp (preg, pattern, cflags)
+ regex_t *__restrict preg;
+ const char *__restrict pattern;
+ int cflags;
+{
+ reg_errcode_t ret;
+ reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED
+ : RE_SYNTAX_POSIX_BASIC);
+
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ preg->used = 0;
+
+ /* Try to allocate space for the fastmap. */
+ preg->fastmap = re_malloc (char, SBC_MAX);
+ if (BE (preg->fastmap == NULL, 0))
+ return REG_ESPACE;
+
+ syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0;
+
+ /* If REG_NEWLINE is set, newlines are treated differently. */
+ if (cflags & REG_NEWLINE)
+ { /* REG_NEWLINE implies neither . nor [^...] match newline. */
+ syntax &= ~RE_DOT_NEWLINE;
+ syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+ /* It also changes the matching behavior. */
+ preg->newline_anchor = 1;
+ }
+ else
+ preg->newline_anchor = 0;
+ preg->no_sub = !!(cflags & REG_NOSUB);
+ preg->translate = NULL;
+
+ ret = re_compile_internal (preg, pattern, strlen (pattern), syntax);
+
+ /* POSIX doesn't distinguish between an unmatched open-group and an
+ unmatched close-group: both are REG_EPAREN. */
+ if (ret == REG_ERPAREN)
+ ret = REG_EPAREN;
+
+ /* We have already checked preg->fastmap != NULL. */
+ if (BE (ret == REG_NOERROR, 1))
+ /* Compute the fastmap now, since regexec cannot modify the pattern
+ buffer. This function never fails in this implementation. */
+ (void) re_compile_fastmap (preg);
+ else
+ {
+ /* Some error occurred while compiling the expression. */
+ re_free (preg->fastmap);
+ preg->fastmap = NULL;
+ }
+
+ return (int) ret;
+}
+#ifdef _LIBC
+weak_alias (__regcomp, regcomp)
+#endif
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+ from either regcomp or regexec. We don't use PREG here. */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+ int errcode;
+ const regex_t *preg;
+ char *errbuf;
+ size_t errbuf_size;
+{
+ const char *msg;
+ size_t msg_size;
+
+ if (BE (errcode < 0
+ || errcode >= (int) (sizeof (__re_error_msgid_idx)
+ / sizeof (__re_error_msgid_idx[0])), 0))
+ /* Only error codes returned by the rest of the code should be passed
+ to this routine. If we are given anything else, or if other regex
+ code generates an invalid error code, then the program has a bug.
+ Dump core so we can fix it. */
+ abort ();
+
+ msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]);
+
+ msg_size = strlen (msg) + 1; /* Includes the null. */
+
+ if (BE (errbuf_size != 0, 1))
+ {
+ if (BE (msg_size > errbuf_size, 0))
+ {
+#if defined HAVE_MEMPCPY || defined _LIBC
+ *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0';
+#else
+ memcpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+#endif
+ }
+ else
+ memcpy (errbuf, msg, msg_size);
+ }
+
+ return msg_size;
+}
+#ifdef _LIBC
+weak_alias (__regerror, regerror)
+#endif
+
+
+#ifdef RE_ENABLE_I18N
+/* This static array is used for the map to single-byte characters when
+ UTF-8 is used. Otherwise we would allocate memory just to initialize
+ it the same all the time. UTF-8 is the preferred encoding so this is
+ a worthwhile optimization. */
+static const bitset utf8_sb_map =
+{
+ /* Set the first 128 bits. */
+# if UINT_MAX == 0xffffffff
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
+# else
+# error "Add case for new unsigned int size"
+# endif
+};
+#endif
+
+
+static void
+free_dfa_content (re_dfa_t *dfa)
+{
+ int i, j;
+
+ if (dfa->nodes)
+ for (i = 0; i < dfa->nodes_len; ++i)
+ free_token (dfa->nodes + i);
+ re_free (dfa->nexts);
+ for (i = 0; i < dfa->nodes_len; ++i)
+ {
+ if (dfa->eclosures != NULL)
+ re_node_set_free (dfa->eclosures + i);
+ if (dfa->inveclosures != NULL)
+ re_node_set_free (dfa->inveclosures + i);
+ if (dfa->edests != NULL)
+ re_node_set_free (dfa->edests + i);
+ }
+ re_free (dfa->edests);
+ re_free (dfa->eclosures);
+ re_free (dfa->inveclosures);
+ re_free (dfa->nodes);
+
+ if (dfa->state_table)
+ for (i = 0; i <= dfa->state_hash_mask; ++i)
+ {
+ struct re_state_table_entry *entry = dfa->state_table + i;
+ for (j = 0; j < entry->num; ++j)
+ {
+ re_dfastate_t *state = entry->array[j];
+ free_state (state);
+ }
+ re_free (entry->array);
+ }
+ re_free (dfa->state_table);
+#ifdef RE_ENABLE_I18N
+ if (dfa->sb_char != utf8_sb_map)
+ re_free (dfa->sb_char);
+#endif
+ re_free (dfa->subexp_map);
+#ifdef DEBUG
+ re_free (dfa->re_str);
+#endif
+
+ re_free (dfa);
+}
+
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+regfree (preg)
+ regex_t *preg;
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ if (BE (dfa != NULL, 1))
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+
+ re_free (preg->fastmap);
+ preg->fastmap = NULL;
+
+ re_free (preg->translate);
+ preg->translate = NULL;
+}
+#ifdef _LIBC
+weak_alias (__regfree, regfree)
+#endif
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+
+/* BSD has one and only one pattern buffer. */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+# ifdef _LIBC
+/* Make these definitions weak in libc, so POSIX programs can redefine
+ these names if they don't use our functions, and still use
+ regcomp/regexec above without link errors. */
+weak_function
+# endif
+re_comp (s)
+ const char *s;
+{
+ reg_errcode_t ret;
+ char *fastmap;
+
+ if (!s)
+ {
+ if (!re_comp_buf.buffer)
+ return gettext ("No previous regular expression");
+ return 0;
+ }
+
+ if (re_comp_buf.buffer)
+ {
+ fastmap = re_comp_buf.fastmap;
+ re_comp_buf.fastmap = NULL;
+ __regfree (&re_comp_buf);
+ memset (&re_comp_buf, '\0', sizeof (re_comp_buf));
+ re_comp_buf.fastmap = fastmap;
+ }
+
+ if (re_comp_buf.fastmap == NULL)
+ {
+ re_comp_buf.fastmap = (char *) malloc (SBC_MAX);
+ if (re_comp_buf.fastmap == NULL)
+ return (char *) gettext (__re_error_msgid
+ + __re_error_msgid_idx[(int) REG_ESPACE]);
+ }
+
+ /* Since `re_exec' always passes NULL for the `regs' argument, we
+ don't need to initialize the pattern buffer fields which affect it. */
+
+ /* Match anchors at newlines. */
+ re_comp_buf.newline_anchor = 1;
+
+ ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options);
+
+ if (!ret)
+ return NULL;
+
+ /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */
+ return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
+}
+
+#ifdef _LIBC
+libc_freeres_fn (free_mem)
+{
+ __regfree (&re_comp_buf);
+}
+#endif
+
+#endif /* _REGEX_RE_COMP */
+
+/* Internal entry point.
+ Compile the regular expression PATTERN, whose length is LENGTH.
+ SYNTAX indicate regular expression's syntax. */
+
+static reg_errcode_t
+re_compile_internal (preg, pattern, length, syntax)
+ regex_t *preg;
+ const char * pattern;
+ int length;
+ reg_syntax_t syntax;
+{
+ reg_errcode_t err = REG_NOERROR;
+ re_dfa_t *dfa;
+ re_string_t regexp;
+
+ /* Initialize the pattern buffer. */
+ preg->fastmap_accurate = 0;
+ preg->syntax = syntax;
+ preg->not_bol = preg->not_eol = 0;
+ preg->used = 0;
+ preg->re_nsub = 0;
+ preg->can_be_null = 0;
+ preg->regs_allocated = REGS_UNALLOCATED;
+
+ /* Initialize the dfa. */
+ dfa = (re_dfa_t *) preg->buffer;
+ if (BE (preg->allocated < sizeof (re_dfa_t), 0))
+ {
+ /* If zero allocated, but buffer is non-null, try to realloc
+ enough space. This loses if buffer's address is bogus, but
+ that is the user's responsibility. If ->buffer is NULL this
+ is a simple allocation. */
+ dfa = re_realloc (preg->buffer, re_dfa_t, 1);
+ if (dfa == NULL)
+ return REG_ESPACE;
+ preg->allocated = sizeof (re_dfa_t);
+ preg->buffer = (unsigned char *) dfa;
+ }
+ preg->used = sizeof (re_dfa_t);
+
+ err = init_dfa (dfa, length);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ return err;
+ }
+#ifdef DEBUG
+ dfa->re_str = re_malloc (char, length + 1);
+ strncpy (dfa->re_str, pattern, length + 1);
+#endif
+
+ err = re_string_construct (&regexp, pattern, length, preg->translate,
+ syntax & RE_ICASE, dfa);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_compile_internal_free_return:
+ free_workarea_compile (preg);
+ re_string_destruct (&regexp);
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ return err;
+ }
+
+ /* Parse the regular expression, and build a structure tree. */
+ preg->re_nsub = 0;
+ dfa->str_tree = parse (&regexp, preg, syntax, &err);
+ if (BE (dfa->str_tree == NULL, 0))
+ goto re_compile_internal_free_return;
+
+ /* Analyze the tree and create the nfa. */
+ err = analyze (preg);
+ if (BE (err != REG_NOERROR, 0))
+ goto re_compile_internal_free_return;
+
+#ifdef RE_ENABLE_I18N
+ /* If possible, do searching in single byte encoding to speed things up. */
+ if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL)
+ optimize_utf8 (dfa);
+#endif
+
+ /* Then create the initial state of the dfa. */
+ err = create_initial_state (dfa);
+
+ /* Release work areas. */
+ free_workarea_compile (preg);
+ re_string_destruct (&regexp);
+
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ }
+
+ return err;
+}
+
+/* Initialize DFA. We use the length of the regular expression PAT_LEN
+ as the initial length of some arrays. */
+
+static reg_errcode_t
+init_dfa (dfa, pat_len)
+ re_dfa_t *dfa;
+ int pat_len;
+{
+ int table_size;
+#ifndef _LIBC
+ char *codeset_name;
+#endif
+
+ memset (dfa, '\0', sizeof (re_dfa_t));
+
+ /* Force allocation of str_tree_storage the first time. */
+ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
+
+ dfa->nodes_alloc = pat_len + 1;
+ dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc);
+
+ dfa->states_alloc = pat_len + 1;
+
+ /* table_size = 2 ^ ceil(log pat_len) */
+ for (table_size = 1; table_size > 0; table_size <<= 1)
+ if (table_size > pat_len)
+ break;
+
+ dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size);
+ dfa->state_hash_mask = table_size - 1;
+
+ dfa->mb_cur_max = MB_CUR_MAX;
+#ifdef _LIBC
+ if (dfa->mb_cur_max == 6
+ && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0)
+ dfa->is_utf8 = 1;
+ dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII)
+ != 0);
+#else
+# ifdef HAVE_LANGINFO_CODESET
+ codeset_name = nl_langinfo (CODESET);
+# else
+ codeset_name = getenv ("LC_ALL");
+ if (codeset_name == NULL || codeset_name[0] == '\0')
+ codeset_name = getenv ("LC_CTYPE");
+ if (codeset_name == NULL || codeset_name[0] == '\0')
+ codeset_name = getenv ("LANG");
+ if (codeset_name == NULL)
+ codeset_name = "";
+ else if (strchr (codeset_name, '.') != NULL)
+ codeset_name = strchr (codeset_name, '.') + 1;
+# endif
+
+ if (strcasecmp (codeset_name, "UTF-8") == 0
+ || strcasecmp (codeset_name, "UTF8") == 0)
+ dfa->is_utf8 = 1;
+
+ /* We check exhaustively in the loop below if this charset is a
+ superset of ASCII. */
+ dfa->map_notascii = 0;
+#endif
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ if (dfa->is_utf8)
+ dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map;
+ else
+ {
+ int i, j, ch;
+
+ dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset), 1);
+ if (BE (dfa->sb_char == NULL, 0))
+ return REG_ESPACE;
+
+ /* Clear all bits by, then set those corresponding to single
+ byte chars. */
+ bitset_empty (dfa->sb_char);
+
+ for (i = 0, ch = 0; i < BITSET_UINTS; ++i)
+ for (j = 0; j < UINT_BITS; ++j, ++ch)
+ {
+ wchar_t wch = __btowc (ch);
+ if (wch != WEOF)
+ dfa->sb_char[i] |= 1 << j;
+# ifndef _LIBC
+ if (isascii (ch) && wch != (wchar_t) ch)
+ dfa->map_notascii = 1;
+# endif
+ }
+ }
+ }
+#endif
+
+ if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0))
+ return REG_ESPACE;
+ return REG_NOERROR;
+}
+
+/* Initialize WORD_CHAR table, which indicate which character is
+ "word". In this case "word" means that it is the word construction
+ character used by some operators like "\<", "\>", etc. */
+
+static void
+init_word_char (dfa)
+ re_dfa_t *dfa;
+{
+ int i, j, ch;
+ dfa->word_ops_used = 1;
+ for (i = 0, ch = 0; i < BITSET_UINTS; ++i)
+ for (j = 0; j < UINT_BITS; ++j, ++ch)
+ if (isalnum (ch) || ch == '_')
+ dfa->word_char[i] |= 1 << j;
+}
+
+/* Free the work area which are only used while compiling. */
+
+static void
+free_workarea_compile (preg)
+ regex_t *preg;
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_storage_t *storage, *next;
+ for (storage = dfa->str_tree_storage; storage; storage = next)
+ {
+ next = storage->next;
+ re_free (storage);
+ }
+ dfa->str_tree_storage = NULL;
+ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
+ dfa->str_tree = NULL;
+ re_free (dfa->org_indices);
+ dfa->org_indices = NULL;
+}
+
+/* Create initial states for all contexts. */
+
+static reg_errcode_t
+create_initial_state (dfa)
+ re_dfa_t *dfa;
+{
+ int first, i;
+ reg_errcode_t err;
+ re_node_set init_nodes;
+
+ /* Initial states have the epsilon closure of the node which is
+ the first node of the regular expression. */
+ first = dfa->str_tree->first->node_idx;
+ dfa->init_node = first;
+ err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* The back-references which are in initial states can epsilon transit,
+ since in this case all of the subexpressions can be null.
+ Then we add epsilon closures of the nodes which are the next nodes of
+ the back-references. */
+ if (dfa->nbackref > 0)
+ for (i = 0; i < init_nodes.nelem; ++i)
+ {
+ int node_idx = init_nodes.elems[i];
+ re_token_type_t type = dfa->nodes[node_idx].type;
+
+ int clexp_idx;
+ if (type != OP_BACK_REF)
+ continue;
+ for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx)
+ {
+ re_token_t *clexp_node;
+ clexp_node = dfa->nodes + init_nodes.elems[clexp_idx];
+ if (clexp_node->type == OP_CLOSE_SUBEXP
+ && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx)
+ break;
+ }
+ if (clexp_idx == init_nodes.nelem)
+ continue;
+
+ if (type == OP_BACK_REF)
+ {
+ int dest_idx = dfa->edests[node_idx].elems[0];
+ if (!re_node_set_contains (&init_nodes, dest_idx))
+ {
+ re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx);
+ i = 0;
+ }
+ }
+ }
+
+ /* It must be the first time to invoke acquire_state. */
+ dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0);
+ /* We don't check ERR here, since the initial state must not be NULL. */
+ if (BE (dfa->init_state == NULL, 0))
+ return err;
+ if (dfa->init_state->has_constraint)
+ {
+ dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
+ CONTEXT_WORD);
+ dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes,
+ CONTEXT_NEWLINE);
+ dfa->init_state_begbuf = re_acquire_state_context (&err, dfa,
+ &init_nodes,
+ CONTEXT_NEWLINE
+ | CONTEXT_BEGBUF);
+ if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL
+ || dfa->init_state_begbuf == NULL, 0))
+ return err;
+ }
+ else
+ dfa->init_state_word = dfa->init_state_nl
+ = dfa->init_state_begbuf = dfa->init_state;
+
+ re_node_set_free (&init_nodes);
+ return REG_NOERROR;
+}
+
+#ifdef RE_ENABLE_I18N
+/* If it is possible to do searching in single byte encoding instead of UTF-8
+ to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change
+ DFA nodes where needed. */
+
+static void
+optimize_utf8 (dfa)
+ re_dfa_t *dfa;
+{
+ int node, i, mb_chars = 0, has_period = 0;
+
+ for (node = 0; node < dfa->nodes_len; ++node)
+ switch (dfa->nodes[node].type)
+ {
+ case CHARACTER:
+ if (dfa->nodes[node].opr.c >= 0x80)
+ mb_chars = 1;
+ break;
+ case ANCHOR:
+ switch (dfa->nodes[node].opr.idx)
+ {
+ case LINE_FIRST:
+ case LINE_LAST:
+ case BUF_FIRST:
+ case BUF_LAST:
+ break;
+ default:
+ /* Word anchors etc. cannot be handled. */
+ return;
+ }
+ break;
+ case OP_PERIOD:
+ has_period = 1;
+ break;
+ case OP_BACK_REF:
+ case OP_ALT:
+ case END_OF_RE:
+ case OP_DUP_ASTERISK:
+ case OP_OPEN_SUBEXP:
+ case OP_CLOSE_SUBEXP:
+ break;
+ case COMPLEX_BRACKET:
+ return;
+ case SIMPLE_BRACKET:
+ /* Just double check. */
+ for (i = 0x80 / UINT_BITS; i < BITSET_UINTS; ++i)
+ if (dfa->nodes[node].opr.sbcset[i])
+ return;
+ break;
+ default:
+ abort ();
+ }
+
+ if (mb_chars || has_period)
+ for (node = 0; node < dfa->nodes_len; ++node)
+ {
+ if (dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].opr.c >= 0x80)
+ dfa->nodes[node].mb_partial = 0;
+ else if (dfa->nodes[node].type == OP_PERIOD)
+ dfa->nodes[node].type = OP_UTF8_PERIOD;
+ }
+
+ /* The search can be in single byte locale. */
+ dfa->mb_cur_max = 1;
+ dfa->is_utf8 = 0;
+ dfa->has_mb_node = dfa->nbackref > 0 || has_period;
+}
+#endif
+
+/* Analyze the structure tree, and calculate "first", "next", "edest",
+ "eclosure", and "inveclosure". */
+
+static reg_errcode_t
+analyze (preg)
+ regex_t *preg;
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ reg_errcode_t ret;
+
+ /* Allocate arrays. */
+ dfa->nexts = re_malloc (int, dfa->nodes_alloc);
+ dfa->org_indices = re_malloc (int, dfa->nodes_alloc);
+ dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc);
+ dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc);
+ if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL
+ || dfa->eclosures == NULL, 0))
+ return REG_ESPACE;
+
+ dfa->subexp_map = re_malloc (int, preg->re_nsub);
+ if (dfa->subexp_map != NULL)
+ {
+ int i;
+ for (i = 0; i < preg->re_nsub; i++)
+ dfa->subexp_map[i] = i;
+ preorder (dfa->str_tree, optimize_subexps, dfa);
+ for (i = 0; i < preg->re_nsub; i++)
+ if (dfa->subexp_map[i] != i)
+ break;
+ if (i == preg->re_nsub)
+ {
+ free (dfa->subexp_map);
+ dfa->subexp_map = NULL;
+ }
+ }
+
+ ret = postorder (dfa->str_tree, lower_subexps, preg);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ ret = postorder (dfa->str_tree, calc_first, dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ preorder (dfa->str_tree, calc_next, dfa);
+ ret = preorder (dfa->str_tree, link_nfa_nodes, dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ ret = calc_eclosure (dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ /* We only need this during the prune_impossible_nodes pass in regexec.c;
+ skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */
+ if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match)
+ || dfa->nbackref)
+ {
+ dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len);
+ if (BE (dfa->inveclosures == NULL, 0))
+ return REG_ESPACE;
+ ret = calc_inveclosure (dfa);
+ }
+
+ return ret;
+}
+
+/* Our parse trees are very unbalanced, so we cannot use a stack to
+ implement parse tree visits. Instead, we use parent pointers and
+ some hairy code in these two functions. */
+static reg_errcode_t
+postorder (root, fn, extra)
+ bin_tree_t *root;
+ reg_errcode_t (fn (void *, bin_tree_t *));
+ void *extra;
+{
+ bin_tree_t *node, *prev;
+
+ for (node = root; ; )
+ {
+ /* Descend down the tree, preferably to the left (or to the right
+ if that's the only child). */
+ while (node->left || node->right)
+ if (node->left)
+ node = node->left;
+ else
+ node = node->right;
+
+ do
+ {
+ reg_errcode_t err = fn (extra, node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ if (node->parent == NULL)
+ return REG_NOERROR;
+ prev = node;
+ node = node->parent;
+ }
+ /* Go up while we have a node that is reached from the right. */
+ while (node->right == prev || node->right == NULL);
+ node = node->right;
+ }
+}
+
+static reg_errcode_t
+preorder (root, fn, extra)
+ bin_tree_t *root;
+ reg_errcode_t (fn (void *, bin_tree_t *));
+ void *extra;
+{
+ bin_tree_t *node;
+
+ for (node = root; ; )
+ {
+ reg_errcode_t err = fn (extra, node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* Go to the left node, or up and to the right. */
+ if (node->left)
+ node = node->left;
+ else
+ {
+ bin_tree_t *prev = NULL;
+ while (node->right == prev || node->right == NULL)
+ {
+ prev = node;
+ node = node->parent;
+ if (!node)
+ return REG_NOERROR;
+ }
+ node = node->right;
+ }
+ }
+}
+
+/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell
+ re_search_internal to map the inner one's opr.idx to this one's. Adjust
+ backreferences as well. Requires a preorder visit. */
+static reg_errcode_t
+optimize_subexps (extra, node)
+ void *extra;
+ bin_tree_t *node;
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+
+ if (node->token.type == OP_BACK_REF && dfa->subexp_map)
+ {
+ int idx = node->token.opr.idx;
+ node->token.opr.idx = dfa->subexp_map[idx];
+ dfa->used_bkref_map |= 1 << node->token.opr.idx;
+ }
+
+ else if (node->token.type == SUBEXP
+ && node->left && node->left->token.type == SUBEXP)
+ {
+ int other_idx = node->left->token.opr.idx;
+
+ node->left = node->left->left;
+ if (node->left)
+ node->left->parent = node;
+
+ dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx];
+ if (other_idx < 8 * sizeof (dfa->used_bkref_map))
+ dfa->used_bkref_map &= ~(1 << other_idx);
+ }
+
+ return REG_NOERROR;
+}
+
+/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation
+ of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */
+static reg_errcode_t
+lower_subexps (extra, node)
+ void *extra;
+ bin_tree_t *node;
+{
+ regex_t *preg = (regex_t *) extra;
+ reg_errcode_t err = REG_NOERROR;
+
+ if (node->left && node->left->token.type == SUBEXP)
+ {
+ node->left = lower_subexp (&err, preg, node->left);
+ if (node->left)
+ node->left->parent = node;
+ }
+ if (node->right && node->right->token.type == SUBEXP)
+ {
+ node->right = lower_subexp (&err, preg, node->right);
+ if (node->right)
+ node->right->parent = node;
+ }
+
+ return err;
+}
+
+static bin_tree_t *
+lower_subexp (err, preg, node)
+ reg_errcode_t *err;
+ regex_t *preg;
+ bin_tree_t *node;
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *body = node->left;
+ bin_tree_t *op, *cls, *tree1, *tree;
+
+ if (preg->no_sub
+ /* We do not optimize empty subexpressions, because otherwise we may
+ have bad CONCAT nodes with NULL children. This is obviously not
+ very common, so we do not lose much. An example that triggers
+ this case is the sed "script" /\(\)/x. */
+ && node->left != NULL
+ && (node->token.opr.idx >= 8 * sizeof (dfa->used_bkref_map)
+ || !(dfa->used_bkref_map & (1 << node->token.opr.idx))))
+ return node->left;
+
+ /* Convert the SUBEXP node to the concatenation of an
+ OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */
+ op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP);
+ cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP);
+ tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls;
+ tree = create_tree (dfa, op, tree1, CONCAT);
+ if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx;
+ op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp;
+ return tree;
+}
+
+/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton
+ nodes. Requires a postorder visit. */
+static reg_errcode_t
+calc_first (extra, node)
+ void *extra;
+ bin_tree_t *node;
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+ if (node->token.type == CONCAT)
+ {
+ node->first = node->left->first;
+ node->node_idx = node->left->node_idx;
+ }
+ else
+ {
+ node->first = node;
+ node->node_idx = re_dfa_add_node (dfa, node->token);
+ if (BE (node->node_idx == -1, 0))
+ return REG_ESPACE;
+ }
+ return REG_NOERROR;
+}
+
+/* Pass 2: compute NEXT on the tree. Preorder visit. */
+static reg_errcode_t
+calc_next (extra, node)
+ void *extra;
+ bin_tree_t *node;
+{
+ switch (node->token.type)
+ {
+ case OP_DUP_ASTERISK:
+ node->left->next = node;
+ break;
+ case CONCAT:
+ node->left->next = node->right->first;
+ node->right->next = node->next;
+ break;
+ default:
+ if (node->left)
+ node->left->next = node->next;
+ if (node->right)
+ node->right->next = node->next;
+ break;
+ }
+ return REG_NOERROR;
+}
+
+/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */
+static reg_errcode_t
+link_nfa_nodes (extra, node)
+ void *extra;
+ bin_tree_t *node;
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+ int idx = node->node_idx;
+ reg_errcode_t err = REG_NOERROR;
+
+ switch (node->token.type)
+ {
+ case CONCAT:
+ break;
+
+ case END_OF_RE:
+ assert (node->next == NULL);
+ break;
+
+ case OP_DUP_ASTERISK:
+ case OP_ALT:
+ {
+ int left, right;
+ dfa->has_plural_match = 1;
+ if (node->left != NULL)
+ left = node->left->first->node_idx;
+ else
+ left = node->next->node_idx;
+ if (node->right != NULL)
+ right = node->right->first->node_idx;
+ else
+ right = node->next->node_idx;
+ assert (left > -1);
+ assert (right > -1);
+ err = re_node_set_init_2 (dfa->edests + idx, left, right);
+ }
+ break;
+
+ case ANCHOR:
+ case OP_OPEN_SUBEXP:
+ case OP_CLOSE_SUBEXP:
+ err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx);
+ break;
+
+ case OP_BACK_REF:
+ dfa->nexts[idx] = node->next->node_idx;
+ if (node->token.type == OP_BACK_REF)
+ re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]);
+ break;
+
+ default:
+ assert (!IS_EPSILON_NODE (node->token.type));
+ dfa->nexts[idx] = node->next->node_idx;
+ break;
+ }
+
+ return err;
+}
+
+/* Duplicate the epsilon closure of the node ROOT_NODE.
+ Note that duplicated nodes have constraint INIT_CONSTRAINT in addition
+ to their own constraint. */
+
+static reg_errcode_t
+duplicate_node_closure (dfa, top_org_node, top_clone_node, root_node,
+ init_constraint)
+ re_dfa_t *dfa;
+ int top_org_node, top_clone_node, root_node;
+ unsigned int init_constraint;
+{
+ reg_errcode_t err;
+ int org_node, clone_node, ret;
+ unsigned int constraint = init_constraint;
+ for (org_node = top_org_node, clone_node = top_clone_node;;)
+ {
+ int org_dest, clone_dest;
+ if (dfa->nodes[org_node].type == OP_BACK_REF)
+ {
+ /* If the back reference epsilon-transit, its destination must
+ also have the constraint. Then duplicate the epsilon closure
+ of the destination of the back reference, and store it in
+ edests of the back reference. */
+ org_dest = dfa->nexts[org_node];
+ re_node_set_empty (dfa->edests + clone_node);
+ err = duplicate_node (&clone_dest, dfa, org_dest, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ dfa->nexts[clone_node] = dfa->nexts[org_node];
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ else if (dfa->edests[org_node].nelem == 0)
+ {
+ /* In case of the node can't epsilon-transit, don't duplicate the
+ destination and store the original destination as the
+ destination of the node. */
+ dfa->nexts[clone_node] = dfa->nexts[org_node];
+ break;
+ }
+ else if (dfa->edests[org_node].nelem == 1)
+ {
+ /* In case of the node can epsilon-transit, and it has only one
+ destination. */
+ org_dest = dfa->edests[org_node].elems[0];
+ re_node_set_empty (dfa->edests + clone_node);
+ if (dfa->nodes[org_node].type == ANCHOR)
+ {
+ /* In case of the node has another constraint, append it. */
+ if (org_node == root_node && clone_node != org_node)
+ {
+ /* ...but if the node is root_node itself, it means the
+ epsilon closure have a loop, then tie it to the
+ destination of the root_node. */
+ ret = re_node_set_insert (dfa->edests + clone_node,
+ org_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ break;
+ }
+ constraint |= dfa->nodes[org_node].opr.ctx_type;
+ }
+ err = duplicate_node (&clone_dest, dfa, org_dest, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ else /* dfa->edests[org_node].nelem == 2 */
+ {
+ /* In case of the node can epsilon-transit, and it has two
+ destinations. In the bin_tree_t and DFA, that's '|' and '*'. */
+ org_dest = dfa->edests[org_node].elems[0];
+ re_node_set_empty (dfa->edests + clone_node);
+ /* Search for a duplicated node which satisfies the constraint. */
+ clone_dest = search_duplicated_node (dfa, org_dest, constraint);
+ if (clone_dest == -1)
+ {
+ /* There are no such a duplicated node, create a new one. */
+ err = duplicate_node (&clone_dest, dfa, org_dest, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ err = duplicate_node_closure (dfa, org_dest, clone_dest,
+ root_node, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ {
+ /* There are a duplicated node which satisfy the constraint,
+ use it to avoid infinite loop. */
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+
+ org_dest = dfa->edests[org_node].elems[1];
+ err = duplicate_node (&clone_dest, dfa, org_dest, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ org_node = org_dest;
+ clone_node = clone_dest;
+ }
+ return REG_NOERROR;
+}
+
+/* Search for a node which is duplicated from the node ORG_NODE, and
+ satisfies the constraint CONSTRAINT. */
+
+static int
+search_duplicated_node (dfa, org_node, constraint)
+ re_dfa_t *dfa;
+ int org_node;
+ unsigned int constraint;
+{
+ int idx;
+ for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx)
+ {
+ if (org_node == dfa->org_indices[idx]
+ && constraint == dfa->nodes[idx].constraint)
+ return idx; /* Found. */
+ }
+ return -1; /* Not found. */
+}
+
+/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT.
+ The new index will be stored in NEW_IDX and return REG_NOERROR if succeeded,
+ otherwise return the error code. */
+
+static reg_errcode_t
+duplicate_node (new_idx, dfa, org_idx, constraint)
+ re_dfa_t *dfa;
+ int *new_idx, org_idx;
+ unsigned int constraint;
+{
+ int dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]);
+ if (BE (dup_idx == -1, 0))
+ return REG_ESPACE;
+ dfa->nodes[dup_idx].constraint = constraint;
+ if (dfa->nodes[org_idx].type == ANCHOR)
+ dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type;
+ dfa->nodes[dup_idx].duplicated = 1;
+
+ /* Store the index of the original node. */
+ dfa->org_indices[dup_idx] = org_idx;
+ *new_idx = dup_idx;
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+calc_inveclosure (dfa)
+ re_dfa_t *dfa;
+{
+ int src, idx, ret;
+ for (idx = 0; idx < dfa->nodes_len; ++idx)
+ re_node_set_init_empty (dfa->inveclosures + idx);
+
+ for (src = 0; src < dfa->nodes_len; ++src)
+ {
+ int *elems = dfa->eclosures[src].elems;
+ for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx)
+ {
+ ret = re_node_set_insert_last (dfa->inveclosures + elems[idx], src);
+ if (BE (ret == -1, 0))
+ return REG_ESPACE;
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Calculate "eclosure" for all the node in DFA. */
+
+static reg_errcode_t
+calc_eclosure (dfa)
+ re_dfa_t *dfa;
+{
+ int node_idx, incomplete;
+#ifdef DEBUG
+ assert (dfa->nodes_len > 0);
+#endif
+ incomplete = 0;
+ /* For each nodes, calculate epsilon closure. */
+ for (node_idx = 0; ; ++node_idx)
+ {
+ reg_errcode_t err;
+ re_node_set eclosure_elem;
+ if (node_idx == dfa->nodes_len)
+ {
+ if (!incomplete)
+ break;
+ incomplete = 0;
+ node_idx = 0;
+ }
+
+#ifdef DEBUG
+ assert (dfa->eclosures[node_idx].nelem != -1);
+#endif
+
+ /* If we have already calculated, skip it. */
+ if (dfa->eclosures[node_idx].nelem != 0)
+ continue;
+ /* Calculate epsilon closure of `node_idx'. */
+ err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, 1);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (dfa->eclosures[node_idx].nelem == 0)
+ {
+ incomplete = 1;
+ re_node_set_free (&eclosure_elem);
+ }
+ }
+ return REG_NOERROR;
+}
+
+/* Calculate epsilon closure of NODE. */
+
+static reg_errcode_t
+calc_eclosure_iter (new_set, dfa, node, root)
+ re_node_set *new_set;
+ re_dfa_t *dfa;
+ int node, root;
+{
+ reg_errcode_t err;
+ unsigned int constraint;
+ int i, incomplete;
+ re_node_set eclosure;
+ incomplete = 0;
+ err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* This indicates that we are calculating this node now.
+ We reference this value to avoid infinite loop. */
+ dfa->eclosures[node].nelem = -1;
+
+ constraint = ((dfa->nodes[node].type == ANCHOR)
+ ? dfa->nodes[node].opr.ctx_type : 0);
+ /* If the current node has constraints, duplicate all nodes.
+ Since they must inherit the constraints. */
+ if (constraint
+ && dfa->edests[node].nelem
+ && !dfa->nodes[dfa->edests[node].elems[0]].duplicated)
+ {
+ int org_node, cur_node;
+ org_node = cur_node = node;
+ err = duplicate_node_closure (dfa, node, node, node, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ /* Expand each epsilon destination nodes. */
+ if (IS_EPSILON_NODE(dfa->nodes[node].type))
+ for (i = 0; i < dfa->edests[node].nelem; ++i)
+ {
+ re_node_set eclosure_elem;
+ int edest = dfa->edests[node].elems[i];
+ /* If calculating the epsilon closure of `edest' is in progress,
+ return intermediate result. */
+ if (dfa->eclosures[edest].nelem == -1)
+ {
+ incomplete = 1;
+ continue;
+ }
+ /* If we haven't calculated the epsilon closure of `edest' yet,
+ calculate now. Otherwise use calculated epsilon closure. */
+ if (dfa->eclosures[edest].nelem == 0)
+ {
+ err = calc_eclosure_iter (&eclosure_elem, dfa, edest, 0);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ eclosure_elem = dfa->eclosures[edest];
+ /* Merge the epsilon closure of `edest'. */
+ re_node_set_merge (&eclosure, &eclosure_elem);
+ /* If the epsilon closure of `edest' is incomplete,
+ the epsilon closure of this node is also incomplete. */
+ if (dfa->eclosures[edest].nelem == 0)
+ {
+ incomplete = 1;
+ re_node_set_free (&eclosure_elem);
+ }
+ }
+
+ /* Epsilon closures include itself. */
+ re_node_set_insert (&eclosure, node);
+ if (incomplete && !root)
+ dfa->eclosures[node].nelem = 0;
+ else
+ dfa->eclosures[node] = eclosure;
+ *new_set = eclosure;
+ return REG_NOERROR;
+}
+
+/* Functions for token which are used in the parser. */
+
+/* Fetch a token from INPUT.
+ We must not use this function inside bracket expressions. */
+
+static void
+fetch_token (result, input, syntax)
+ re_token_t *result;
+ re_string_t *input;
+ reg_syntax_t syntax;
+{
+ re_string_skip_bytes (input, peek_token (result, input, syntax));
+}
+
+/* Peek a token from INPUT, and return the length of the token.
+ We must not use this function inside bracket expressions. */
+
+static int
+peek_token (token, input, syntax)
+ re_token_t *token;
+ re_string_t *input;
+ reg_syntax_t syntax;
+{
+ unsigned char c;
+
+ if (re_string_eoi (input))
+ {
+ token->type = END_OF_RE;
+ return 0;
+ }
+
+ c = re_string_peek_byte (input, 0);
+ token->opr.c = c;
+
+ token->word_char = 0;
+#ifdef RE_ENABLE_I18N
+ token->mb_partial = 0;
+ if (input->mb_cur_max > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+ token->mb_partial = 1;
+ return 1;
+ }
+#endif
+ if (c == '\\')
+ {
+ unsigned char c2;
+ if (re_string_cur_idx (input) + 1 >= re_string_length (input))
+ {
+ token->type = BACK_SLASH;
+ return 1;
+ }
+
+ c2 = re_string_peek_byte_case (input, 1);
+ token->opr.c = c2;
+ token->type = CHARACTER;
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc = re_string_wchar_at (input,
+ re_string_cur_idx (input) + 1);
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+ }
+ else
+#endif
+ token->word_char = IS_WORD_CHAR (c2) != 0;
+
+ switch (c2)
+ {
+ case '|':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR))
+ token->type = OP_ALT;
+ break;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ if (!(syntax & RE_NO_BK_REFS))
+ {
+ token->type = OP_BACK_REF;
+ token->opr.idx = c2 - '1';
+ }
+ break;
+ case '<':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_FIRST;
+ }
+ break;
+ case '>':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_LAST;
+ }
+ break;
+ case 'b':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_DELIM;
+ }
+ break;
+ case 'B':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = NOT_WORD_DELIM;
+ }
+ break;
+ case 'w':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_WORD;
+ break;
+ case 'W':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_NOTWORD;
+ break;
+ case 's':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_SPACE;
+ break;
+ case 'S':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_NOTSPACE;
+ break;
+ case '`':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = BUF_FIRST;
+ }
+ break;
+ case '\'':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = BUF_LAST;
+ }
+ break;
+ case '(':
+ if (!(syntax & RE_NO_BK_PARENS))
+ token->type = OP_OPEN_SUBEXP;
+ break;
+ case ')':
+ if (!(syntax & RE_NO_BK_PARENS))
+ token->type = OP_CLOSE_SUBEXP;
+ break;
+ case '+':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_PLUS;
+ break;
+ case '?':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_QUESTION;
+ break;
+ case '{':
+ if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
+ token->type = OP_OPEN_DUP_NUM;
+ break;
+ case '}':
+ if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
+ token->type = OP_CLOSE_DUP_NUM;
+ break;
+ default:
+ break;
+ }
+ return 2;
+ }
+
+ token->type = CHARACTER;
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input));
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+ }
+ else
+#endif
+ token->word_char = IS_WORD_CHAR (token->opr.c);
+
+ switch (c)
+ {
+ case '\n':
+ if (syntax & RE_NEWLINE_ALT)
+ token->type = OP_ALT;
+ break;
+ case '|':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR))
+ token->type = OP_ALT;
+ break;
+ case '*':
+ token->type = OP_DUP_ASTERISK;
+ break;
+ case '+':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_PLUS;
+ break;
+ case '?':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_QUESTION;
+ break;
+ case '{':
+ if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ token->type = OP_OPEN_DUP_NUM;
+ break;
+ case '}':
+ if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ token->type = OP_CLOSE_DUP_NUM;
+ break;
+ case '(':
+ if (syntax & RE_NO_BK_PARENS)
+ token->type = OP_OPEN_SUBEXP;
+ break;
+ case ')':
+ if (syntax & RE_NO_BK_PARENS)
+ token->type = OP_CLOSE_SUBEXP;
+ break;
+ case '[':
+ token->type = OP_OPEN_BRACKET;
+ break;
+ case '.':
+ token->type = OP_PERIOD;
+ break;
+ case '^':
+ if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) &&
+ re_string_cur_idx (input) != 0)
+ {
+ char prev = re_string_peek_byte (input, -1);
+ if (!(syntax & RE_NEWLINE_ALT) || prev != '\n')
+ break;
+ }
+ token->type = ANCHOR;
+ token->opr.ctx_type = LINE_FIRST;
+ break;
+ case '$':
+ if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) &&
+ re_string_cur_idx (input) + 1 != re_string_length (input))
+ {
+ re_token_t next;
+ re_string_skip_bytes (input, 1);
+ peek_token (&next, input, syntax);
+ re_string_skip_bytes (input, -1);
+ if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP)
+ break;
+ }
+ token->type = ANCHOR;
+ token->opr.ctx_type = LINE_LAST;
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+/* Peek a token from INPUT, and return the length of the token.
+ We must not use this function out of bracket expressions. */
+
+static int
+peek_token_bracket (token, input, syntax)
+ re_token_t *token;
+ re_string_t *input;
+ reg_syntax_t syntax;
+{
+ unsigned char c;
+ if (re_string_eoi (input))
+ {
+ token->type = END_OF_RE;
+ return 0;
+ }
+ c = re_string_peek_byte (input, 0);
+ token->opr.c = c;
+
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+ return 1;
+ }
+#endif /* RE_ENABLE_I18N */
+
+ if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS)
+ && re_string_cur_idx (input) + 1 < re_string_length (input))
+ {
+ /* In this case, '\' escape a character. */
+ unsigned char c2;
+ re_string_skip_bytes (input, 1);
+ c2 = re_string_peek_byte (input, 0);
+ token->opr.c = c2;
+ token->type = CHARACTER;
+ return 1;
+ }
+ if (c == '[') /* '[' is a special char in a bracket exps. */
+ {
+ unsigned char c2;
+ int token_len;
+ if (re_string_cur_idx (input) + 1 < re_string_length (input))
+ c2 = re_string_peek_byte (input, 1);
+ else
+ c2 = 0;
+ token->opr.c = c2;
+ token_len = 2;
+ switch (c2)
+ {
+ case '.':
+ token->type = OP_OPEN_COLL_ELEM;
+ break;
+ case '=':
+ token->type = OP_OPEN_EQUIV_CLASS;
+ break;
+ case ':':
+ if (syntax & RE_CHAR_CLASSES)
+ {
+ token->type = OP_OPEN_CHAR_CLASS;
+ break;
+ }
+ /* else fall through. */
+ default:
+ token->type = CHARACTER;
+ token->opr.c = c;
+ token_len = 1;
+ break;
+ }
+ return token_len;
+ }
+ switch (c)
+ {
+ case '-':
+ token->type = OP_CHARSET_RANGE;
+ break;
+ case ']':
+ token->type = OP_CLOSE_BRACKET;
+ break;
+ case '^':
+ token->type = OP_NON_MATCH_LIST;
+ break;
+ default:
+ token->type = CHARACTER;
+ }
+ return 1;
+}
+
+/* Functions for parser. */
+
+/* Entry point of the parser.
+ Parse the regular expression REGEXP and return the structure tree.
+ If an error is occured, ERR is set by error code, and return NULL.
+ This function build the following tree, from regular expression <reg_exp>:
+ CAT
+ / \
+ / \
+ <reg_exp> EOR
+
+ CAT means concatenation.
+ EOR means end of regular expression. */
+
+static bin_tree_t *
+parse (regexp, preg, syntax, err)
+ re_string_t *regexp;
+ regex_t *preg;
+ reg_syntax_t syntax;
+ reg_errcode_t *err;
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree, *eor, *root;
+ re_token_t current_token;
+ dfa->syntax = syntax;
+ fetch_token (&current_token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+ tree = parse_reg_exp (regexp, preg, &current_token, syntax, 0, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ eor = create_tree (dfa, NULL, NULL, END_OF_RE);
+ if (tree != NULL)
+ root = create_tree (dfa, tree, eor, CONCAT);
+ else
+ root = eor;
+ if (BE (eor == NULL || root == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ return root;
+}
+
+/* This function build the following tree, from regular expression
+ <branch1>|<branch2>:
+ ALT
+ / \
+ / \
+ <branch1> <branch2>
+
+ ALT means alternative, which represents the operator `|'. */
+
+static bin_tree_t *
+parse_reg_exp (regexp, preg, token, syntax, nest, err)
+ re_string_t *regexp;
+ regex_t *preg;
+ re_token_t *token;
+ reg_syntax_t syntax;
+ int nest;
+ reg_errcode_t *err;
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree, *branch = NULL;
+ tree = parse_branch (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+
+ while (token->type == OP_ALT)
+ {
+ fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+ if (token->type != OP_ALT && token->type != END_OF_RE
+ && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
+ {
+ branch = parse_branch (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && branch == NULL, 0))
+ return NULL;
+ }
+ else
+ branch = NULL;
+ tree = create_tree (dfa, tree, branch, OP_ALT);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ return tree;
+}
+
+/* This function build the following tree, from regular expression
+ <exp1><exp2>:
+ CAT
+ / \
+ / \
+ <exp1> <exp2>
+
+ CAT means concatenation. */
+
+static bin_tree_t *
+parse_branch (regexp, preg, token, syntax, nest, err)
+ re_string_t *regexp;
+ regex_t *preg;
+ re_token_t *token;
+ reg_syntax_t syntax;
+ int nest;
+ reg_errcode_t *err;
+{
+ bin_tree_t *tree, *exp;
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ tree = parse_expression (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+
+ while (token->type != OP_ALT && token->type != END_OF_RE
+ && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
+ {
+ exp = parse_expression (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && exp == NULL, 0))
+ {
+ return NULL;
+ }
+ if (tree != NULL && exp != NULL)
+ {
+ tree = create_tree (dfa, tree, exp, CONCAT);
+ if (tree == NULL)
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ else if (tree == NULL)
+ tree = exp;
+ /* Otherwise exp == NULL, we don't need to create new tree. */
+ }
+ return tree;
+}
+
+/* This function build the following tree, from regular expression a*:
+ *
+ |
+ a
+*/
+
+static bin_tree_t *
+parse_expression (regexp, preg, token, syntax, nest, err)
+ re_string_t *regexp;
+ regex_t *preg;
+ re_token_t *token;
+ reg_syntax_t syntax;
+ int nest;
+ reg_errcode_t *err;
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree;
+ switch (token->type)
+ {
+ case CHARACTER:
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ while (!re_string_eoi (regexp)
+ && !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
+ {
+ bin_tree_t *mbc_remain;
+ fetch_token (token, regexp, syntax);
+ mbc_remain = create_token_tree (dfa, NULL, NULL, token);
+ tree = create_tree (dfa, tree, mbc_remain, CONCAT);
+ if (BE (mbc_remain == NULL || tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ }
+#endif
+ break;
+ case OP_OPEN_SUBEXP:
+ tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_OPEN_BRACKET:
+ tree = parse_bracket_exp (regexp, dfa, token, syntax, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_BACK_REF:
+ if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1))
+ {
+ *err = REG_ESUBREG;
+ return NULL;
+ }
+ dfa->used_bkref_map |= 1 << token->opr.idx;
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ ++dfa->nbackref;
+ dfa->has_mb_node = 1;
+ break;
+ case OP_OPEN_DUP_NUM:
+ if (syntax & RE_CONTEXT_INVALID_DUP)
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ /* FALLTHROUGH */
+ case OP_DUP_ASTERISK:
+ case OP_DUP_PLUS:
+ case OP_DUP_QUESTION:
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ else if (syntax & RE_CONTEXT_INDEP_OPS)
+ {
+ fetch_token (token, regexp, syntax);
+ return parse_expression (regexp, preg, token, syntax, nest, err);
+ }
+ /* else fall through */
+ case OP_CLOSE_SUBEXP:
+ if ((token->type == OP_CLOSE_SUBEXP) &&
+ !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD))
+ {
+ *err = REG_ERPAREN;
+ return NULL;
+ }
+ /* else fall through */
+ case OP_CLOSE_DUP_NUM:
+ /* We treat it as a normal character. */
+
+ /* Then we can these characters as normal characters. */
+ token->type = CHARACTER;
+ /* mb_partial and word_char bits should be initialized already
+ by peek_token. */
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ break;
+ case ANCHOR:
+ if ((token->opr.ctx_type
+ & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST))
+ && dfa->word_ops_used == 0)
+ init_word_char (dfa);
+ if (token->opr.ctx_type == WORD_DELIM
+ || token->opr.ctx_type == NOT_WORD_DELIM)
+ {
+ bin_tree_t *tree_first, *tree_last;
+ if (token->opr.ctx_type == WORD_DELIM)
+ {
+ token->opr.ctx_type = WORD_FIRST;
+ tree_first = create_token_tree (dfa, NULL, NULL, token);
+ token->opr.ctx_type = WORD_LAST;
+ }
+ else
+ {
+ token->opr.ctx_type = INSIDE_WORD;
+ tree_first = create_token_tree (dfa, NULL, NULL, token);
+ token->opr.ctx_type = INSIDE_NOTWORD;
+ }
+ tree_last = create_token_tree (dfa, NULL, NULL, token);
+ tree = create_tree (dfa, tree_first, tree_last, OP_ALT);
+ if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ else
+ {
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ /* We must return here, since ANCHORs can't be followed
+ by repetition operators.
+ eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>",
+ it must not be "<ANCHOR(^)><REPEAT(*)>". */
+ fetch_token (token, regexp, syntax);
+ return tree;
+ case OP_PERIOD:
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ if (dfa->mb_cur_max > 1)
+ dfa->has_mb_node = 1;
+ break;
+ case OP_WORD:
+ case OP_NOTWORD:
+ tree = build_charclass_op (dfa, regexp->trans,
+ (const unsigned char *) "alnum",
+ (const unsigned char *) "_",
+ token->type == OP_NOTWORD, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_SPACE:
+ case OP_NOTSPACE:
+ tree = build_charclass_op (dfa, regexp->trans,
+ (const unsigned char *) "space",
+ (const unsigned char *) "",
+ token->type == OP_NOTSPACE, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_ALT:
+ case END_OF_RE:
+ return NULL;
+ case BACK_SLASH:
+ *err = REG_EESCAPE;
+ return NULL;
+ default:
+ /* Must not happen? */
+#ifdef DEBUG
+ assert (0);
+#endif
+ return NULL;
+ }
+ fetch_token (token, regexp, syntax);
+
+ while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS
+ || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM)
+ {
+ tree = parse_dup_op (tree, regexp, dfa, token, syntax, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ /* In BRE consecutive duplications are not allowed. */
+ if ((syntax & RE_CONTEXT_INVALID_DUP)
+ && (token->type == OP_DUP_ASTERISK
+ || token->type == OP_OPEN_DUP_NUM))
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ }
+
+ return tree;
+}
+
+/* This function build the following tree, from regular expression
+ (<reg_exp>):
+ SUBEXP
+ |
+ <reg_exp>
+*/
+
+static bin_tree_t *
+parse_sub_exp (regexp, preg, token, syntax, nest, err)
+ re_string_t *regexp;
+ regex_t *preg;
+ re_token_t *token;
+ reg_syntax_t syntax;
+ int nest;
+ reg_errcode_t *err;
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree;
+ size_t cur_nsub;
+ cur_nsub = preg->re_nsub++;
+
+ fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+
+ /* The subexpression may be a null string. */
+ if (token->type == OP_CLOSE_SUBEXP)
+ tree = NULL;
+ else
+ {
+ tree = parse_reg_exp (regexp, preg, token, syntax, nest, err);
+ if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0))
+ *err = REG_EPAREN;
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+ dfa->completed_bkref_map |= 1 << cur_nsub;
+
+ tree = create_tree (dfa, tree, NULL, SUBEXP);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ tree->token.opr.idx = cur_nsub;
+ return tree;
+}
+
+/* This function parse repetition operators like "*", "+", "{1,3}" etc. */
+
+static bin_tree_t *
+parse_dup_op (elem, regexp, dfa, token, syntax, err)
+ bin_tree_t *elem;
+ re_string_t *regexp;
+ re_dfa_t *dfa;
+ re_token_t *token;
+ reg_syntax_t syntax;
+ reg_errcode_t *err;
+{
+ bin_tree_t *tree = NULL, *old_tree = NULL;
+ int i, start, end, start_idx = re_string_cur_idx (regexp);
+ re_token_t start_token = *token;
+
+ if (token->type == OP_OPEN_DUP_NUM)
+ {
+ end = 0;
+ start = fetch_number (regexp, token, syntax);
+ if (start == -1)
+ {
+ if (token->type == CHARACTER && token->opr.c == ',')
+ start = 0; /* We treat "{,m}" as "{0,m}". */
+ else
+ {
+ *err = REG_BADBR; /* <re>{} is invalid. */
+ return NULL;
+ }
+ }
+ if (BE (start != -2, 1))
+ {
+ /* We treat "{n}" as "{n,n}". */
+ end = ((token->type == OP_CLOSE_DUP_NUM) ? start
+ : ((token->type == CHARACTER && token->opr.c == ',')
+ ? fetch_number (regexp, token, syntax) : -2));
+ }
+ if (BE (start == -2 || end == -2, 0))
+ {
+ /* Invalid sequence. */
+ if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0))
+ {
+ if (token->type == END_OF_RE)
+ *err = REG_EBRACE;
+ else
+ *err = REG_BADBR;
+
+ return NULL;
+ }
+
+ /* If the syntax bit is set, rollback. */
+ re_string_set_index (regexp, start_idx);
+ *token = start_token;
+ token->type = CHARACTER;
+ /* mb_partial and word_char bits should be already initialized by
+ peek_token. */
+ return elem;
+ }
+
+ if (BE (end != -1 && start > end, 0))
+ {
+ /* First number greater than second. */
+ *err = REG_BADBR;
+ return NULL;
+ }
+ }
+ else
+ {
+ start = (token->type == OP_DUP_PLUS) ? 1 : 0;
+ end = (token->type == OP_DUP_QUESTION) ? 1 : -1;
+ }
+
+ fetch_token (token, regexp, syntax);
+
+ if (BE (elem == NULL, 0))
+ return NULL;
+ if (BE (start == 0 && end == 0, 0))
+ {
+ postorder (elem, free_tree, NULL);
+ return NULL;
+ }
+
+ /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */
+ if (BE (start > 0, 0))
+ {
+ tree = elem;
+ for (i = 2; i <= start; ++i)
+ {
+ elem = duplicate_tree (elem, dfa);
+ tree = create_tree (dfa, tree, elem, CONCAT);
+ if (BE (elem == NULL || tree == NULL, 0))
+ goto parse_dup_op_espace;
+ }
+
+ if (start == end)
+ return tree;
+
+ /* Duplicate ELEM before it is marked optional. */
+ elem = duplicate_tree (elem, dfa);
+ old_tree = tree;
+ }
+ else
+ old_tree = NULL;
+
+ if (elem->token.type == SUBEXP)
+ postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx);
+
+ tree = create_tree (dfa, elem, NULL, (end == -1 ? OP_DUP_ASTERISK : OP_ALT));
+ if (BE (tree == NULL, 0))
+ goto parse_dup_op_espace;
+
+ /* This loop is actually executed only when end != -1,
+ to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have
+ already created the start+1-th copy. */
+ for (i = start + 2; i <= end; ++i)
+ {
+ elem = duplicate_tree (elem, dfa);
+ tree = create_tree (dfa, tree, elem, CONCAT);
+ if (BE (elem == NULL || tree == NULL, 0))
+ goto parse_dup_op_espace;
+
+ tree = create_tree (dfa, tree, NULL, OP_ALT);
+ if (BE (tree == NULL, 0))
+ goto parse_dup_op_espace;
+ }
+
+ if (old_tree)
+ tree = create_tree (dfa, old_tree, tree, CONCAT);
+
+ return tree;
+
+ parse_dup_op_espace:
+ *err = REG_ESPACE;
+ return NULL;
+}
+
+/* Size of the names for collating symbol/equivalence_class/character_class.
+ I'm not sure, but maybe enough. */
+#define BRACKET_NAME_BUF_SIZE 32
+
+#ifndef _LIBC
+ /* Local function for parse_bracket_exp only used in case of NOT _LIBC.
+ Build the range expression which starts from START_ELEM, and ends
+ at END_ELEM. The result are written to MBCSET and SBCSET.
+ RANGE_ALLOC is the allocated size of mbcset->range_starts, and
+ mbcset->range_ends, is a pointer argument sinse we may
+ update it. */
+
+static reg_errcode_t
+# ifdef RE_ENABLE_I18N
+build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem)
+ re_charset_t *mbcset;
+ int *range_alloc;
+# else /* not RE_ENABLE_I18N */
+build_range_exp (sbcset, start_elem, end_elem)
+# endif /* not RE_ENABLE_I18N */
+ re_bitset_ptr_t sbcset;
+ bracket_elem_t *start_elem, *end_elem;
+{
+ unsigned int start_ch, end_ch;
+ /* Equivalence Classes and Character Classes can't be a range start/end. */
+ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
+ || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
+ 0))
+ return REG_ERANGE;
+
+ /* We can handle no multi character collating elements without libc
+ support. */
+ if (BE ((start_elem->type == COLL_SYM
+ && strlen ((char *) start_elem->opr.name) > 1)
+ || (end_elem->type == COLL_SYM
+ && strlen ((char *) end_elem->opr.name) > 1), 0))
+ return REG_ECOLLATE;
+
+# ifdef RE_ENABLE_I18N
+ {
+ wchar_t wc, start_wc, end_wc;
+ wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
+
+ start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch
+ : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
+ : 0));
+ end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch
+ : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
+ : 0));
+ start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM)
+ ? __btowc (start_ch) : start_elem->opr.wch);
+ end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM)
+ ? __btowc (end_ch) : end_elem->opr.wch);
+ if (start_wc == WEOF || end_wc == WEOF)
+ return REG_ECOLLATE;
+ cmp_buf[0] = start_wc;
+ cmp_buf[4] = end_wc;
+ if (wcscoll (cmp_buf, cmp_buf + 4) > 0)
+ return REG_ERANGE;
+
+ /* Got valid collation sequence values, add them as a new entry.
+ However, for !_LIBC we have no collation elements: if the
+ character set is single byte, the single byte character set
+ that we build below suffices. parse_bracket_exp passes
+ no MBCSET if dfa->mb_cur_max == 1. */
+ if (mbcset)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+ {
+ /* There is not enough space, need realloc. */
+ wchar_t *new_array_start, *new_array_end;
+ int new_nranges;
+
+ /* +1 in case of mbcset->nranges is 0. */
+ new_nranges = 2 * mbcset->nranges + 1;
+ /* Use realloc since mbcset->range_starts and mbcset->range_ends
+ are NULL if *range_alloc == 0. */
+ new_array_start = re_realloc (mbcset->range_starts, wchar_t,
+ new_nranges);
+ new_array_end = re_realloc (mbcset->range_ends, wchar_t,
+ new_nranges);
+
+ if (BE (new_array_start == NULL || new_array_end == NULL, 0))
+ return REG_ESPACE;
+
+ mbcset->range_starts = new_array_start;
+ mbcset->range_ends = new_array_end;
+ *range_alloc = new_nranges;
+ }
+
+ mbcset->range_starts[mbcset->nranges] = start_wc;
+ mbcset->range_ends[mbcset->nranges++] = end_wc;
+ }
+
+ /* Build the table for single byte characters. */
+ for (wc = 0; wc < SBC_MAX; ++wc)
+ {
+ cmp_buf[2] = wc;
+ if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
+ && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
+ bitset_set (sbcset, wc);
+ }
+ }
+# else /* not RE_ENABLE_I18N */
+ {
+ unsigned int ch;
+ start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch
+ : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
+ : 0));
+ end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch
+ : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
+ : 0));
+ if (start_ch > end_ch)
+ return REG_ERANGE;
+ /* Build the table for single byte characters. */
+ for (ch = 0; ch < SBC_MAX; ++ch)
+ if (start_ch <= ch && ch <= end_ch)
+ bitset_set (sbcset, ch);
+ }
+# endif /* not RE_ENABLE_I18N */
+ return REG_NOERROR;
+}
+#endif /* not _LIBC */
+
+#ifndef _LIBC
+/* Helper function for parse_bracket_exp only used in case of NOT _LIBC..
+ Build the collating element which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
+ pointer argument since we may update it. */
+
+static reg_errcode_t
+# ifdef RE_ENABLE_I18N
+build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name)
+ re_charset_t *mbcset;
+ int *coll_sym_alloc;
+# else /* not RE_ENABLE_I18N */
+build_collating_symbol (sbcset, name)
+# endif /* not RE_ENABLE_I18N */
+ re_bitset_ptr_t sbcset;
+ const unsigned char *name;
+{
+ size_t name_len = strlen ((const char *) name);
+ if (BE (name_len != 1, 0))
+ return REG_ECOLLATE;
+ else
+ {
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+}
+#endif /* not _LIBC */
+
+/* This function parse bracket expression like "[abc]", "[a-c]",
+ "[[.a-a.]]" etc. */
+
+static bin_tree_t *
+parse_bracket_exp (regexp, dfa, token, syntax, err)
+ re_string_t *regexp;
+ re_dfa_t *dfa;
+ re_token_t *token;
+ reg_syntax_t syntax;
+ reg_errcode_t *err;
+{
+#ifdef _LIBC
+ const unsigned char *collseqmb;
+ const char *collseqwc;
+ uint32_t nrules;
+ int32_t table_size;
+ const int32_t *symb_table;
+ const unsigned char *extra;
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Seek the collating symbol entry correspondings to NAME.
+ Return the index of the symbol in the SYMB_TABLE. */
+
+ auto inline int32_t
+ __attribute ((always_inline))
+ seek_collating_symbol_entry (name, name_len)
+ const unsigned char *name;
+ size_t name_len;
+ {
+ int32_t hash = elem_hash ((const char *) name, name_len);
+ int32_t elem = hash % table_size;
+ int32_t second = hash % (table_size - 2);
+ while (symb_table[2 * elem] != 0)
+ {
+ /* First compare the hashing value. */
+ if (symb_table[2 * elem] == hash
+ /* Compare the length of the name. */
+ && name_len == extra[symb_table[2 * elem + 1]]
+ /* Compare the name. */
+ && memcmp (name, &extra[symb_table[2 * elem + 1] + 1],
+ name_len) == 0)
+ {
+ /* Yep, this is the entry. */
+ break;
+ }
+
+ /* Next entry. */
+ elem += second;
+ }
+ return elem;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Look up the collation sequence value of BR_ELEM.
+ Return the value if succeeded, UINT_MAX otherwise. */
+
+ auto inline unsigned int
+ __attribute ((always_inline))
+ lookup_collation_sequence_value (br_elem)
+ bracket_elem_t *br_elem;
+ {
+ if (br_elem->type == SB_CHAR)
+ {
+ /*
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+ return collseqmb[br_elem->opr.ch];
+ else
+ {
+ wint_t wc = __btowc (br_elem->opr.ch);
+ return __collseq_table_lookup (collseqwc, wc);
+ }
+ }
+ else if (br_elem->type == MB_CHAR)
+ {
+ return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
+ }
+ else if (br_elem->type == COLL_SYM)
+ {
+ size_t sym_name_len = strlen ((char *) br_elem->opr.name);
+ if (nrules != 0)
+ {
+ int32_t elem, idx;
+ elem = seek_collating_symbol_entry (br_elem->opr.name,
+ sym_name_len);
+ if (symb_table[2 * elem] != 0)
+ {
+ /* We found the entry. */
+ idx = symb_table[2 * elem + 1];
+ /* Skip the name of collating element name. */
+ idx += 1 + extra[idx];
+ /* Skip the byte sequence of the collating element. */
+ idx += 1 + extra[idx];
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+ /* Skip the multibyte collation sequence value. */
+ idx += sizeof (unsigned int);
+ /* Skip the wide char sequence of the collating element. */
+ idx += sizeof (unsigned int) *
+ (1 + *(unsigned int *) (extra + idx));
+ /* Return the collation sequence value. */
+ return *(unsigned int *) (extra + idx);
+ }
+ else if (symb_table[2 * elem] == 0 && sym_name_len == 1)
+ {
+ /* No valid character. Match it as a single byte
+ character. */
+ return collseqmb[br_elem->opr.name[0]];
+ }
+ }
+ else if (sym_name_len == 1)
+ return collseqmb[br_elem->opr.name[0]];
+ }
+ return UINT_MAX;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Build the range expression which starts from START_ELEM, and ends
+ at END_ELEM. The result are written to MBCSET and SBCSET.
+ RANGE_ALLOC is the allocated size of mbcset->range_starts, and
+ mbcset->range_ends, is a pointer argument sinse we may
+ update it. */
+
+ auto inline reg_errcode_t
+ __attribute ((always_inline))
+ build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem)
+ re_charset_t *mbcset;
+ int *range_alloc;
+ re_bitset_ptr_t sbcset;
+ bracket_elem_t *start_elem, *end_elem;
+ {
+ unsigned int ch;
+ uint32_t start_collseq;
+ uint32_t end_collseq;
+
+ /* Equivalence Classes and Character Classes can't be a range
+ start/end. */
+ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
+ || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
+ 0))
+ return REG_ERANGE;
+
+ start_collseq = lookup_collation_sequence_value (start_elem);
+ end_collseq = lookup_collation_sequence_value (end_elem);
+ /* Check start/end collation sequence values. */
+ if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0))
+ return REG_ECOLLATE;
+ if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0))
+ return REG_ERANGE;
+
+ /* Got valid collation sequence values, add them as a new entry.
+ However, if we have no collation elements, and the character set
+ is single byte, the single byte character set that we
+ build below suffices. */
+ if (nrules > 0 || dfa->mb_cur_max > 1)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+ {
+ /* There is not enough space, need realloc. */
+ uint32_t *new_array_start;
+ uint32_t *new_array_end;
+ int new_nranges;
+
+ /* +1 in case of mbcset->nranges is 0. */
+ new_nranges = 2 * mbcset->nranges + 1;
+ new_array_start = re_realloc (mbcset->range_starts, uint32_t,
+ new_nranges);
+ new_array_end = re_realloc (mbcset->range_ends, uint32_t,
+ new_nranges);
+
+ if (BE (new_array_start == NULL || new_array_end == NULL, 0))
+ return REG_ESPACE;
+
+ mbcset->range_starts = new_array_start;
+ mbcset->range_ends = new_array_end;
+ *range_alloc = new_nranges;
+ }
+
+ mbcset->range_starts[mbcset->nranges] = start_collseq;
+ mbcset->range_ends[mbcset->nranges++] = end_collseq;
+ }
+
+ /* Build the table for single byte characters. */
+ for (ch = 0; ch < SBC_MAX; ch++)
+ {
+ uint32_t ch_collseq;
+ /*
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+ ch_collseq = collseqmb[ch];
+ else
+ ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
+ if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
+ bitset_set (sbcset, ch);
+ }
+ return REG_NOERROR;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Build the collating element which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
+ pointer argument sinse we may update it. */
+
+ auto inline reg_errcode_t
+ __attribute ((always_inline))
+ build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name)
+ re_charset_t *mbcset;
+ int *coll_sym_alloc;
+ re_bitset_ptr_t sbcset;
+ const unsigned char *name;
+ {
+ int32_t elem, idx;
+ size_t name_len = strlen ((const char *) name);
+ if (nrules != 0)
+ {
+ elem = seek_collating_symbol_entry (name, name_len);
+ if (symb_table[2 * elem] != 0)
+ {
+ /* We found the entry. */
+ idx = symb_table[2 * elem + 1];
+ /* Skip the name of collating element name. */
+ idx += 1 + extra[idx];
+ }
+ else if (symb_table[2 * elem] == 0 && name_len == 1)
+ {
+ /* No valid character, treat it as a normal
+ character. */
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+ else
+ return REG_ECOLLATE;
+
+ /* Got valid collation sequence, add it as a new entry. */
+ /* Check the space of the arrays. */
+ if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->ncoll_syms is 0. */
+ int new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1;
+ /* Use realloc since mbcset->coll_syms is NULL
+ if *alloc == 0. */
+ int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t,
+ new_coll_sym_alloc);
+ if (BE (new_coll_syms == NULL, 0))
+ return REG_ESPACE;
+ mbcset->coll_syms = new_coll_syms;
+ *coll_sym_alloc = new_coll_sym_alloc;
+ }
+ mbcset->coll_syms[mbcset->ncoll_syms++] = idx;
+ return REG_NOERROR;
+ }
+ else
+ {
+ if (BE (name_len != 1, 0))
+ return REG_ECOLLATE;
+ else
+ {
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+ }
+ }
+#endif
+
+ re_token_t br_token;
+ re_bitset_ptr_t sbcset;
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset;
+ int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0;
+ int equiv_class_alloc = 0, char_class_alloc = 0;
+#endif /* not RE_ENABLE_I18N */
+ int non_match = 0;
+ bin_tree_t *work_tree;
+ int token_len;
+ int first_round = 1;
+#ifdef _LIBC
+ collseqmb = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules)
+ {
+ /*
+ if (MB_CUR_MAX > 1)
+ */
+ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB);
+ symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_TABLEMB);
+ extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_EXTRAMB);
+ }
+#endif
+ sbcset = (re_bitset_ptr_t) calloc (sizeof (unsigned int), BITSET_UINTS);
+#ifdef RE_ENABLE_I18N
+ mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
+#endif /* RE_ENABLE_I18N */
+#ifdef RE_ENABLE_I18N
+ if (BE (sbcset == NULL || mbcset == NULL, 0))
+#else
+ if (BE (sbcset == NULL, 0))
+#endif /* RE_ENABLE_I18N */
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ token_len = peek_token_bracket (token, regexp, syntax);
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_BADPAT;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_NON_MATCH_LIST)
+ {
+#ifdef RE_ENABLE_I18N
+ mbcset->non_match = 1;
+#endif /* not RE_ENABLE_I18N */
+ non_match = 1;
+ if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+ bitset_set (sbcset, '\0');
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ token_len = peek_token_bracket (token, regexp, syntax);
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_BADPAT;
+ goto parse_bracket_exp_free_return;
+ }
+ }
+
+ /* We treat the first ']' as a normal character. */
+ if (token->type == OP_CLOSE_BRACKET)
+ token->type = CHARACTER;
+
+ while (1)
+ {
+ bracket_elem_t start_elem, end_elem;
+ unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE];
+ unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE];
+ reg_errcode_t ret;
+ int token_len2 = 0, is_range_exp = 0;
+ re_token_t token2;
+
+ start_elem.opr.name = start_name_buf;
+ ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa,
+ syntax, first_round);
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ *err = ret;
+ goto parse_bracket_exp_free_return;
+ }
+ first_round = 0;
+
+ /* Get information about the next token. We need it in any case. */
+ token_len = peek_token_bracket (token, regexp, syntax);
+
+ /* Do not check for ranges if we know they are not allowed. */
+ if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS)
+ {
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_CHARSET_RANGE)
+ {
+ re_string_skip_bytes (regexp, token_len); /* Skip '-'. */
+ token_len2 = peek_token_bracket (&token2, regexp, syntax);
+ if (BE (token2.type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token2.type == OP_CLOSE_BRACKET)
+ {
+ /* We treat the last '-' as a normal character. */
+ re_string_skip_bytes (regexp, -token_len);
+ token->type = CHARACTER;
+ }
+ else
+ is_range_exp = 1;
+ }
+ }
+
+ if (is_range_exp == 1)
+ {
+ end_elem.opr.name = end_name_buf;
+ ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2,
+ dfa, syntax, 1);
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ *err = ret;
+ goto parse_bracket_exp_free_return;
+ }
+
+ token_len = peek_token_bracket (token, regexp, syntax);
+
+#ifdef _LIBC
+ *err = build_range_exp (sbcset, mbcset, &range_alloc,
+ &start_elem, &end_elem);
+#else
+# ifdef RE_ENABLE_I18N
+ *err = build_range_exp (sbcset,
+ dfa->mb_cur_max > 1 ? mbcset : NULL,
+ &range_alloc, &start_elem, &end_elem);
+# else
+ *err = build_range_exp (sbcset, &start_elem, &end_elem);
+# endif
+#endif /* RE_ENABLE_I18N */
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ }
+ else
+ {
+ switch (start_elem.type)
+ {
+ case SB_CHAR:
+ bitset_set (sbcset, start_elem.opr.ch);
+ break;
+#ifdef RE_ENABLE_I18N
+ case MB_CHAR:
+ /* Check whether the array has enough space. */
+ if (BE (mbchar_alloc == mbcset->nmbchars, 0))
+ {
+ wchar_t *new_mbchars;
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nmbchars is 0. */
+ mbchar_alloc = 2 * mbcset->nmbchars + 1;
+ /* Use realloc since array is NULL if *alloc == 0. */
+ new_mbchars = re_realloc (mbcset->mbchars, wchar_t,
+ mbchar_alloc);
+ if (BE (new_mbchars == NULL, 0))
+ goto parse_bracket_exp_espace;
+ mbcset->mbchars = new_mbchars;
+ }
+ mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
+ break;
+#endif /* RE_ENABLE_I18N */
+ case EQUIV_CLASS:
+ *err = build_equiv_class (sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &equiv_class_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ case COLL_SYM:
+ *err = build_collating_symbol (sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &coll_sym_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ case CHAR_CLASS:
+ *err = build_charclass (regexp->trans, sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &char_class_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name, syntax);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ default:
+ assert (0);
+ break;
+ }
+ }
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_CLOSE_BRACKET)
+ break;
+ }
+
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+
+ /* If it is non-matching list. */
+ if (non_match)
+ bitset_not (sbcset);
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+ if (dfa->mb_cur_max > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+
+ if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes
+ || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes
+ || mbcset->non_match)))
+ {
+ bin_tree_t *mbc_tree;
+ int sbc_idx;
+ /* Build a tree for complex bracket. */
+ dfa->has_mb_node = 1;
+ br_token.type = COMPLEX_BRACKET;
+ br_token.opr.mbcset = mbcset;
+ mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (mbc_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ for (sbc_idx = 0; sbc_idx < BITSET_UINTS; ++sbc_idx)
+ if (sbcset[sbc_idx])
+ break;
+ /* If there are no bits set in sbcset, there is no point
+ of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */
+ if (sbc_idx < BITSET_UINTS)
+ {
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+
+ /* Then join them by ALT node. */
+ work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ }
+ else
+ {
+ re_free (sbcset);
+ work_tree = mbc_tree;
+ }
+ }
+ else
+#endif /* not RE_ENABLE_I18N */
+ {
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ }
+ return work_tree;
+
+ parse_bracket_exp_espace:
+ *err = REG_ESPACE;
+ parse_bracket_exp_free_return:
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ return NULL;
+}
+
+/* Parse an element in the bracket expression. */
+
+static reg_errcode_t
+parse_bracket_element (elem, regexp, token, token_len, dfa, syntax,
+ accept_hyphen)
+ bracket_elem_t *elem;
+ re_string_t *regexp;
+ re_token_t *token;
+ int token_len;
+ re_dfa_t *dfa;
+ reg_syntax_t syntax;
+ int accept_hyphen;
+{
+#ifdef RE_ENABLE_I18N
+ int cur_char_size;
+ cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp));
+ if (cur_char_size > 1)
+ {
+ elem->type = MB_CHAR;
+ elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp));
+ re_string_skip_bytes (regexp, cur_char_size);
+ return REG_NOERROR;
+ }
+#endif /* RE_ENABLE_I18N */
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS
+ || token->type == OP_OPEN_EQUIV_CLASS)
+ return parse_bracket_symbol (elem, regexp, token);
+ if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen)
+ {
+ /* A '-' must only appear as anything but a range indicator before
+ the closing bracket. Everything else is an error. */
+ re_token_t token2;
+ (void) peek_token_bracket (&token2, regexp, syntax);
+ if (token2.type != OP_CLOSE_BRACKET)
+ /* The actual error value is not standardized since this whole
+ case is undefined. But ERANGE makes good sense. */
+ return REG_ERANGE;
+ }
+ elem->type = SB_CHAR;
+ elem->opr.ch = token->opr.c;
+ return REG_NOERROR;
+}
+
+/* Parse a bracket symbol in the bracket expression. Bracket symbols are
+ such as [:<character_class>:], [.<collating_element>.], and
+ [=<equivalent_class>=]. */
+
+static reg_errcode_t
+parse_bracket_symbol (elem, regexp, token)
+ bracket_elem_t *elem;
+ re_string_t *regexp;
+ re_token_t *token;
+{
+ unsigned char ch, delim = token->opr.c;
+ int i = 0;
+ if (re_string_eoi(regexp))
+ return REG_EBRACK;
+ for (;; ++i)
+ {
+ if (i >= BRACKET_NAME_BUF_SIZE)
+ return REG_EBRACK;
+ if (token->type == OP_OPEN_CHAR_CLASS)
+ ch = re_string_fetch_byte_case (regexp);
+ else
+ ch = re_string_fetch_byte (regexp);
+ if (re_string_eoi(regexp))
+ return REG_EBRACK;
+ if (ch == delim && re_string_peek_byte (regexp, 0) == ']')
+ break;
+ elem->opr.name[i] = ch;
+ }
+ re_string_skip_bytes (regexp, 1);
+ elem->opr.name[i] = '\0';
+ switch (token->type)
+ {
+ case OP_OPEN_COLL_ELEM:
+ elem->type = COLL_SYM;
+ break;
+ case OP_OPEN_EQUIV_CLASS:
+ elem->type = EQUIV_CLASS;
+ break;
+ case OP_OPEN_CHAR_CLASS:
+ elem->type = CHAR_CLASS;
+ break;
+ default:
+ break;
+ }
+ return REG_NOERROR;
+}
+
+ /* Helper function for parse_bracket_exp.
+ Build the equivalence class which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes,
+ is a pointer argument sinse we may update it. */
+
+static reg_errcode_t
+#ifdef RE_ENABLE_I18N
+build_equiv_class (sbcset, mbcset, equiv_class_alloc, name)
+ re_charset_t *mbcset;
+ int *equiv_class_alloc;
+#else /* not RE_ENABLE_I18N */
+build_equiv_class (sbcset, name)
+#endif /* not RE_ENABLE_I18N */
+ re_bitset_ptr_t sbcset;
+ const unsigned char *name;
+{
+#if defined _LIBC
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+ const int32_t *table, *indirect;
+ const unsigned char *weights, *extra, *cp;
+ unsigned char char_buf[2];
+ int32_t idx1, idx2;
+ unsigned int ch;
+ size_t len;
+ /* This #include defines a local function! */
+# include <locale/weight.h>
+ /* Calculate the index for equivalence class. */
+ cp = name;
+ table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_WEIGHTMB);
+ extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_INDIRECTMB);
+ idx1 = findidx (&cp);
+ if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0))
+ /* This isn't a valid character. */
+ return REG_ECOLLATE;
+
+ /* Build single byte matcing table for this equivalence class. */
+ char_buf[1] = (unsigned char) '\0';
+ len = weights[idx1];
+ for (ch = 0; ch < SBC_MAX; ++ch)
+ {
+ char_buf[0] = ch;
+ cp = char_buf;
+ idx2 = findidx (&cp);
+/*
+ idx2 = table[ch];
+*/
+ if (idx2 == 0)
+ /* This isn't a valid character. */
+ continue;
+ if (len == weights[idx2])
+ {
+ int cnt = 0;
+ while (cnt <= len &&
+ weights[idx1 + 1 + cnt] == weights[idx2 + 1 + cnt])
+ ++cnt;
+
+ if (cnt > len)
+ bitset_set (sbcset, ch);
+ }
+ }
+ /* Check whether the array has enough space. */
+ if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nequiv_classes is 0. */
+ int new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1;
+ /* Use realloc since the array is NULL if *alloc == 0. */
+ int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes,
+ int32_t,
+ new_equiv_class_alloc);
+ if (BE (new_equiv_classes == NULL, 0))
+ return REG_ESPACE;
+ mbcset->equiv_classes = new_equiv_classes;
+ *equiv_class_alloc = new_equiv_class_alloc;
+ }
+ mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1;
+ }
+ else
+#endif /* _LIBC */
+ {
+ if (BE (strlen ((const char *) name) != 1, 0))
+ return REG_ECOLLATE;
+ bitset_set (sbcset, *name);
+ }
+ return REG_NOERROR;
+}
+
+ /* Helper function for parse_bracket_exp.
+ Build the character class which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes,
+ is a pointer argument sinse we may update it. */
+
+static reg_errcode_t
+#ifdef RE_ENABLE_I18N
+build_charclass (trans, sbcset, mbcset, char_class_alloc, class_name, syntax)
+ re_charset_t *mbcset;
+ int *char_class_alloc;
+#else /* not RE_ENABLE_I18N */
+build_charclass (trans, sbcset, class_name, syntax)
+#endif /* not RE_ENABLE_I18N */
+ unsigned RE_TRANSLATE_TYPE trans;
+ re_bitset_ptr_t sbcset;
+ const unsigned char *class_name;
+ reg_syntax_t syntax;
+{
+ int i;
+ const char *name = (const char *) class_name;
+
+ /* In case of REG_ICASE "upper" and "lower" match the both of
+ upper and lower cases. */
+ if ((syntax & RE_ICASE)
+ && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0))
+ name = "alpha";
+
+#ifdef RE_ENABLE_I18N
+ /* Check the space of the arrays. */
+ if (BE (*char_class_alloc == mbcset->nchar_classes, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nchar_classes is 0. */
+ int new_char_class_alloc = 2 * mbcset->nchar_classes + 1;
+ /* Use realloc since array is NULL if *alloc == 0. */
+ wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t,
+ new_char_class_alloc);
+ if (BE (new_char_classes == NULL, 0))
+ return REG_ESPACE;
+ mbcset->char_classes = new_char_classes;
+ *char_class_alloc = new_char_class_alloc;
+ }
+ mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name);
+#endif /* RE_ENABLE_I18N */
+
+#define BUILD_CHARCLASS_LOOP(ctype_func) \
+ for (i = 0; i < SBC_MAX; ++i) \
+ { \
+ if (ctype_func (i)) \
+ { \
+ int ch = trans ? trans[i] : i; \
+ bitset_set (sbcset, ch); \
+ } \
+ }
+
+ if (strcmp (name, "alnum") == 0)
+ BUILD_CHARCLASS_LOOP (isalnum)
+ else if (strcmp (name, "cntrl") == 0)
+ BUILD_CHARCLASS_LOOP (iscntrl)
+ else if (strcmp (name, "lower") == 0)
+ BUILD_CHARCLASS_LOOP (islower)
+ else if (strcmp (name, "space") == 0)
+ BUILD_CHARCLASS_LOOP (isspace)
+ else if (strcmp (name, "alpha") == 0)
+ BUILD_CHARCLASS_LOOP (isalpha)
+ else if (strcmp (name, "digit") == 0)
+ BUILD_CHARCLASS_LOOP (isdigit)
+ else if (strcmp (name, "print") == 0)
+ BUILD_CHARCLASS_LOOP (isprint)
+ else if (strcmp (name, "upper") == 0)
+ BUILD_CHARCLASS_LOOP (isupper)
+ else if (strcmp (name, "blank") == 0)
+ BUILD_CHARCLASS_LOOP (isblank)
+ else if (strcmp (name, "graph") == 0)
+ BUILD_CHARCLASS_LOOP (isgraph)
+ else if (strcmp (name, "punct") == 0)
+ BUILD_CHARCLASS_LOOP (ispunct)
+ else if (strcmp (name, "xdigit") == 0)
+ BUILD_CHARCLASS_LOOP (isxdigit)
+ else
+ return REG_ECTYPE;
+
+ return REG_NOERROR;
+}
+
+static bin_tree_t *
+build_charclass_op (dfa, trans, class_name, extra, non_match, err)
+ re_dfa_t *dfa;
+ unsigned RE_TRANSLATE_TYPE trans;
+ const unsigned char *class_name;
+ const unsigned char *extra;
+ int non_match;
+ reg_errcode_t *err;
+{
+ re_bitset_ptr_t sbcset;
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset;
+ int alloc = 0;
+#endif /* not RE_ENABLE_I18N */
+ reg_errcode_t ret;
+ re_token_t br_token;
+ bin_tree_t *tree;
+
+ sbcset = (re_bitset_ptr_t) calloc (sizeof (unsigned int), BITSET_UINTS);
+#ifdef RE_ENABLE_I18N
+ mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
+#endif /* RE_ENABLE_I18N */
+
+#ifdef RE_ENABLE_I18N
+ if (BE (sbcset == NULL || mbcset == NULL, 0))
+#else /* not RE_ENABLE_I18N */
+ if (BE (sbcset == NULL, 0))
+#endif /* not RE_ENABLE_I18N */
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ if (non_match)
+ {
+#ifdef RE_ENABLE_I18N
+ /*
+ if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+ bitset_set(cset->sbcset, '\0');
+ */
+ mbcset->non_match = 1;
+#endif /* not RE_ENABLE_I18N */
+ }
+
+ /* We don't care the syntax in this case. */
+ ret = build_charclass (trans, sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &alloc,
+#endif /* RE_ENABLE_I18N */
+ class_name, 0);
+
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ *err = ret;
+ return NULL;
+ }
+ /* \w match '_' also. */
+ for (; *extra; extra++)
+ bitset_set (sbcset, *extra);
+
+ /* If it is non-matching list. */
+ if (non_match)
+ bitset_not (sbcset);
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+ if (dfa->mb_cur_max > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+#endif
+
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (tree == NULL, 0))
+ goto build_word_op_espace;
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ bin_tree_t *mbc_tree;
+ /* Build a tree for complex bracket. */
+ br_token.type = COMPLEX_BRACKET;
+ br_token.opr.mbcset = mbcset;
+ dfa->has_mb_node = 1;
+ mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (mbc_tree == NULL, 0))
+ goto build_word_op_espace;
+ /* Then join them by ALT node. */
+ tree = create_tree (dfa, tree, mbc_tree, OP_ALT);
+ if (BE (mbc_tree != NULL, 1))
+ return tree;
+ }
+ else
+ {
+ free_charset (mbcset);
+ return tree;
+ }
+#else /* not RE_ENABLE_I18N */
+ return tree;
+#endif /* not RE_ENABLE_I18N */
+
+ build_word_op_espace:
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ *err = REG_ESPACE;
+ return NULL;
+}
+
+/* This is intended for the expressions like "a{1,3}".
+ Fetch a number from `input', and return the number.
+ Return -1, if the number field is empty like "{,1}".
+ Return -2, If an error is occured. */
+
+static int
+fetch_number (input, token, syntax)
+ re_string_t *input;
+ re_token_t *token;
+ reg_syntax_t syntax;
+{
+ int num = -1;
+ unsigned char c;
+ while (1)
+ {
+ fetch_token (token, input, syntax);
+ c = token->opr.c;
+ if (BE (token->type == END_OF_RE, 0))
+ return -2;
+ if (token->type == OP_CLOSE_DUP_NUM || c == ',')
+ break;
+ num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2)
+ ? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0'));
+ num = (num > RE_DUP_MAX) ? -2 : num;
+ }
+ return num;
+}
+
+#ifdef RE_ENABLE_I18N
+static void
+free_charset (re_charset_t *cset)
+{
+ re_free (cset->mbchars);
+# ifdef _LIBC
+ re_free (cset->coll_syms);
+ re_free (cset->equiv_classes);
+ re_free (cset->range_starts);
+ re_free (cset->range_ends);
+# endif
+ re_free (cset->char_classes);
+ re_free (cset);
+}
+#endif /* RE_ENABLE_I18N */
+
+/* Functions for binary tree operation. */
+
+/* Create a tree node. */
+
+static bin_tree_t *
+create_tree (dfa, left, right, type)
+ re_dfa_t *dfa;
+ bin_tree_t *left;
+ bin_tree_t *right;
+ re_token_type_t type;
+{
+ re_token_t t;
+ t.type = type;
+ return create_token_tree (dfa, left, right, &t);
+}
+
+static bin_tree_t *
+create_token_tree (dfa, left, right, token)
+ re_dfa_t *dfa;
+ bin_tree_t *left;
+ bin_tree_t *right;
+ const re_token_t *token;
+{
+ bin_tree_t *tree;
+ if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0))
+ {
+ bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1);
+
+ if (storage == NULL)
+ return NULL;
+ storage->next = dfa->str_tree_storage;
+ dfa->str_tree_storage = storage;
+ dfa->str_tree_storage_idx = 0;
+ }
+ tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++];
+
+ tree->parent = NULL;
+ tree->left = left;
+ tree->right = right;
+ tree->token = *token;
+ tree->token.duplicated = 0;
+ tree->token.opt_subexp = 0;
+ tree->first = NULL;
+ tree->next = NULL;
+ tree->node_idx = -1;
+
+ if (left != NULL)
+ left->parent = tree;
+ if (right != NULL)
+ right->parent = tree;
+ return tree;
+}
+
+/* Mark the tree SRC as an optional subexpression.
+ To be called from preorder or postorder. */
+
+static reg_errcode_t
+mark_opt_subexp (extra, node)
+ void *extra;
+ bin_tree_t *node;
+{
+ int idx = (int) (long) extra;
+ if (node->token.type == SUBEXP && node->token.opr.idx == idx)
+ node->token.opt_subexp = 1;
+
+ return REG_NOERROR;
+}
+
+/* Free the allocated memory inside NODE. */
+
+static void
+free_token (re_token_t *node)
+{
+#ifdef RE_ENABLE_I18N
+ if (node->type == COMPLEX_BRACKET && node->duplicated == 0)
+ free_charset (node->opr.mbcset);
+ else
+#endif /* RE_ENABLE_I18N */
+ if (node->type == SIMPLE_BRACKET && node->duplicated == 0)
+ re_free (node->opr.sbcset);
+}
+
+/* Worker function for tree walking. Free the allocated memory inside NODE
+ and its children. */
+
+static reg_errcode_t
+free_tree (void *extra, bin_tree_t *node)
+{
+ free_token (&node->token);
+ return REG_NOERROR;
+}
+
+
+/* Duplicate the node SRC, and return new node. This is a preorder
+ visit similar to the one implemented by the generic visitor, but
+ we need more infrastructure to maintain two parallel trees --- so,
+ it's easier to duplicate. */
+
+static bin_tree_t *
+duplicate_tree (root, dfa)
+ const bin_tree_t *root;
+ re_dfa_t *dfa;
+{
+ const bin_tree_t *node;
+ bin_tree_t *dup_root;
+ bin_tree_t **p_new = &dup_root, *dup_node = root->parent;
+
+ for (node = root; ; )
+ {
+ /* Create a new tree and link it back to the current parent. */
+ *p_new = create_token_tree (dfa, NULL, NULL, &node->token);
+ if (*p_new == NULL)
+ return NULL;
+ (*p_new)->parent = dup_node;
+ (*p_new)->token.duplicated = 1;
+ dup_node = *p_new;
+
+ /* Go to the left node, or up and to the right. */
+ if (node->left)
+ {
+ node = node->left;
+ p_new = &dup_node->left;
+ }
+ else
+ {
+ const bin_tree_t *prev = NULL;
+ while (node->right == prev || node->right == NULL)
+ {
+ prev = node;
+ node = node->parent;
+ dup_node = dup_node->parent;
+ if (!node)
+ return dup_root;
+ }
+ node = node->right;
+ p_new = &dup_node->right;
+ }
+ }
+}
diff --git a/gnu/lib/libregex/regex.c b/gnu/lib/libregex/regex.c
new file mode 100644
index 0000000..df7abe2
--- /dev/null
+++ b/gnu/lib/libregex/regex.c
@@ -0,0 +1,98 @@
+/* $FreeBSD$ */
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _AIX
+#pragma alloca
+#else
+# ifndef allocax /* predefined by HP cc +Olibcalls */
+# ifdef __GNUC__
+# define alloca(size) __builtin_alloca (size)
+# else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef __hpux
+ void *alloca ();
+# else
+# if !defined __OS2__ && !defined WIN32
+ char *alloca ();
+# else
+# include <malloc.h> /* OS/2 defines alloca in here */
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef _LIBC
+/* We have to keep the namespace clean. */
+# define regfree(preg) __regfree (preg)
+# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
+# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
+# define regerror(errcode, preg, errbuf, errbuf_size) \
+ __regerror(errcode, preg, errbuf, errbuf_size)
+# define re_set_registers(bu, re, nu, st, en) \
+ __re_set_registers (bu, re, nu, st, en)
+# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
+ __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+# define re_match(bufp, string, size, pos, regs) \
+ __re_match (bufp, string, size, pos, regs)
+# define re_search(bufp, string, size, startpos, range, regs) \
+ __re_search (bufp, string, size, startpos, range, regs)
+# define re_compile_pattern(pattern, length, bufp) \
+ __re_compile_pattern (pattern, length, bufp)
+# define re_set_syntax(syntax) __re_set_syntax (syntax)
+# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
+ __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
+# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
+
+# include "../locale/localeinfo.h"
+#endif
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
+#include <sys/types.h>
+
+/* On some systems, limits.h sets RE_DUP_MAX to a lower value than
+ GNU regex allows. Include it before <regex.h>, which correctly
+ #undefs RE_DUP_MAX and sets it to the right value. */
+#include <limits.h>
+
+#include <regex.h>
+#include "regex_internal.h"
+
+#include "regex_internal.c"
+#include "regcomp.c"
+#include "regexec.c"
+
+/* Binary backward compatibility. */
+#if _LIBC
+# include <shlib-compat.h>
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
+link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.")
+int re_max_failures = 2000;
+# endif
+#endif
diff --git a/gnu/lib/libregex/regex.h b/gnu/lib/libregex/regex.h
new file mode 100644
index 0000000..364966d
--- /dev/null
+++ b/gnu/lib/libregex/regex.h
@@ -0,0 +1,47 @@
+/* $FreeBSD$ */
+#ifndef _REGEX_H
+#include <posix/regex.h>
+
+/* Document internal interfaces. */
+extern reg_syntax_t __re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+extern const char *__re_compile_pattern
+ _RE_ARGS ((const char *pattern, size_t length,
+ struct re_pattern_buffer *buffer));
+
+extern int __re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+extern int __re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int range, struct re_registers *regs));
+
+extern int __re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
+
+extern int __re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+extern int __re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int stop));
+
+extern void __re_set_registers
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+extern int __regcomp _RE_ARGS ((regex_t *__preg, const char *__pattern,
+ int __cflags));
+
+extern int __regexec _RE_ARGS ((const regex_t *__preg,
+ const char *__string, size_t __nmatch,
+ regmatch_t __pmatch[], int __eflags));
+
+extern size_t __regerror _RE_ARGS ((int __errcode, const regex_t *__preg,
+ char *__errbuf, size_t __errbuf_size));
+
+extern void __regfree _RE_ARGS ((regex_t *__preg));
+#endif
diff --git a/gnu/lib/libregex/regex_internal.c b/gnu/lib/libregex/regex_internal.c
new file mode 100644
index 0000000..b3d44c3
--- /dev/null
+++ b/gnu/lib/libregex/regex_internal.c
@@ -0,0 +1,1674 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static void re_string_construct_common (const char *str, int len,
+ re_string_t *pstr,
+ RE_TRANSLATE_TYPE trans, int icase,
+ const re_dfa_t *dfa) internal_function;
+#ifdef RE_ENABLE_I18N
+static int re_string_skip_chars (re_string_t *pstr, int new_raw_idx,
+ wint_t *last_wc) internal_function;
+#endif /* RE_ENABLE_I18N */
+static reg_errcode_t register_state (re_dfa_t *dfa, re_dfastate_t *newstate,
+ unsigned int hash) internal_function;
+static re_dfastate_t *create_ci_newstate (re_dfa_t *dfa,
+ const re_node_set *nodes,
+ unsigned int hash) internal_function;
+static re_dfastate_t *create_cd_newstate (re_dfa_t *dfa,
+ const re_node_set *nodes,
+ unsigned int context,
+ unsigned int hash) internal_function;
+static unsigned int inline calc_state_hash (const re_node_set *nodes,
+ unsigned int context) internal_function;
+
+/* Functions for string operation. */
+
+/* This function allocate the buffers. It is necessary to call
+ re_string_reconstruct before using the object. */
+
+static reg_errcode_t
+re_string_allocate (pstr, str, len, init_len, trans, icase, dfa)
+ re_string_t *pstr;
+ const char *str;
+ int len, init_len, icase;
+ RE_TRANSLATE_TYPE trans;
+ const re_dfa_t *dfa;
+{
+ reg_errcode_t ret;
+ int init_buf_len;
+
+ /* Ensure at least one character fits into the buffers. */
+ if (init_len < dfa->mb_cur_max)
+ init_len = dfa->mb_cur_max;
+ init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+ ret = re_string_realloc_buffers (pstr, init_buf_len);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ pstr->word_char = dfa->word_char;
+ pstr->word_ops_used = dfa->word_ops_used;
+ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
+ pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len;
+ pstr->valid_raw_len = pstr->valid_len;
+ return REG_NOERROR;
+}
+
+/* This function allocate the buffers, and initialize them. */
+
+static reg_errcode_t
+re_string_construct (pstr, str, len, trans, icase, dfa)
+ re_string_t *pstr;
+ const char *str;
+ int len, icase;
+ RE_TRANSLATE_TYPE trans;
+ const re_dfa_t *dfa;
+{
+ reg_errcode_t ret;
+ memset (pstr, '\0', sizeof (re_string_t));
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+ if (len > 0)
+ {
+ ret = re_string_realloc_buffers (pstr, len + 1);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
+
+ if (icase)
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ while (1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ if (pstr->valid_raw_len >= len)
+ break;
+ if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
+ break;
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ build_upper_buffer (pstr);
+ }
+ else
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ build_wcs_buffer (pstr);
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ if (trans != NULL)
+ re_string_translate_buffer (pstr);
+ else
+ {
+ pstr->valid_len = pstr->bufs_len;
+ pstr->valid_raw_len = pstr->bufs_len;
+ }
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Helper functions for re_string_allocate, and re_string_construct. */
+
+static reg_errcode_t
+re_string_realloc_buffers (pstr, new_buf_len)
+ re_string_t *pstr;
+ int new_buf_len;
+{
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ wint_t *new_array = re_realloc (pstr->wcs, wint_t, new_buf_len);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ pstr->wcs = new_array;
+ if (pstr->offsets != NULL)
+ {
+ int *new_array = re_realloc (pstr->offsets, int, new_buf_len);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ pstr->offsets = new_array;
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ if (pstr->mbs_allocated)
+ {
+ unsigned char *new_array = re_realloc (pstr->mbs, unsigned char,
+ new_buf_len);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ pstr->mbs = new_array;
+ }
+ pstr->bufs_len = new_buf_len;
+ return REG_NOERROR;
+}
+
+
+static void
+re_string_construct_common (str, len, pstr, trans, icase, dfa)
+ const char *str;
+ int len;
+ re_string_t *pstr;
+ RE_TRANSLATE_TYPE trans;
+ int icase;
+ const re_dfa_t *dfa;
+{
+ pstr->raw_mbs = (const unsigned char *) str;
+ pstr->len = len;
+ pstr->raw_len = len;
+ pstr->trans = (unsigned RE_TRANSLATE_TYPE) trans;
+ pstr->icase = icase ? 1 : 0;
+ pstr->mbs_allocated = (trans != NULL || icase);
+ pstr->mb_cur_max = dfa->mb_cur_max;
+ pstr->is_utf8 = dfa->is_utf8;
+ pstr->map_notascii = dfa->map_notascii;
+ pstr->stop = pstr->len;
+ pstr->raw_stop = pstr->stop;
+}
+
+#ifdef RE_ENABLE_I18N
+
+/* Build wide character buffer PSTR->WCS.
+ If the byte sequence of the string are:
+ <mb1>(0), <mb1>(1), <mb2>(0), <mb2>(1), <sb3>
+ Then wide character buffer will be:
+ <wc1> , WEOF , <wc2> , WEOF , <wc3>
+ We use WEOF for padding, they indicate that the position isn't
+ a first byte of a multibyte character.
+
+ Note that this function assumes PSTR->VALID_LEN elements are already
+ built and starts from PSTR->VALID_LEN. */
+
+static void
+build_wcs_buffer (pstr)
+ re_string_t *pstr;
+{
+#ifdef _LIBC
+ unsigned char buf[MB_CUR_MAX];
+ assert (MB_CUR_MAX >= pstr->mb_cur_max);
+#else
+ unsigned char buf[64];
+#endif
+ mbstate_t prev_st;
+ int byte_idx, end_idx, remain_len;
+ size_t mbclen;
+
+ /* Build the buffers from pstr->valid_len to either pstr->len or
+ pstr->bufs_len. */
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+ for (byte_idx = pstr->valid_len; byte_idx < end_idx;)
+ {
+ wchar_t wc;
+ const char *p;
+
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ /* Apply the translation if we need. */
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i, ch;
+
+ for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i];
+ buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch];
+ }
+ p = (const char *) buf;
+ }
+ else
+ p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx;
+ mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state);
+ if (BE (mbclen == (size_t) -2, 0))
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0))
+ {
+ /* We treat these cases as a singlebyte character. */
+ mbclen = 1;
+ wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
+ if (BE (pstr->trans != NULL, 0))
+ wc = pstr->trans[wc];
+ pstr->cur_state = prev_st;
+ }
+
+ /* Write wide character and padding. */
+ pstr->wcs[byte_idx++] = wc;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = byte_idx;
+}
+
+/* Build wide character buffer PSTR->WCS like build_wcs_buffer,
+ but for REG_ICASE. */
+
+static int
+build_wcs_upper_buffer (pstr)
+ re_string_t *pstr;
+{
+ mbstate_t prev_st;
+ int src_idx, byte_idx, end_idx, remain_len;
+ size_t mbclen;
+#ifdef _LIBC
+ char buf[MB_CUR_MAX];
+ assert (MB_CUR_MAX >= pstr->mb_cur_max);
+#else
+ char buf[64];
+#endif
+
+ byte_idx = pstr->valid_len;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ /* The following optimization assumes that ASCII characters can be
+ mapped to wide characters with a simple cast. */
+ if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed)
+ {
+ while (byte_idx < end_idx)
+ {
+ wchar_t wc;
+
+ if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx])
+ && mbsinit (&pstr->cur_state))
+ {
+ /* In case of a singlebyte character. */
+ pstr->mbs[byte_idx]
+ = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]);
+ /* The next step uses the assumption that wchar_t is encoded
+ ASCII-safe: all ASCII values can be converted like this. */
+ pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx];
+ ++byte_idx;
+ continue;
+ }
+
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ mbclen = mbrtowc (&wc,
+ ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
+ + byte_idx), remain_len, &pstr->cur_state);
+ if (BE (mbclen + 2 > 2, 1))
+ {
+ wchar_t wcu = wc;
+ if (iswlower (wc))
+ {
+ size_t mbcdlen;
+
+ wcu = towupper (wc);
+ mbcdlen = wcrtomb (buf, wcu, &prev_st);
+ if (BE (mbclen == mbcdlen, 1))
+ memcpy (pstr->mbs + byte_idx, buf, mbclen);
+ else
+ {
+ src_idx = byte_idx;
+ goto offsets_needed;
+ }
+ }
+ else
+ memcpy (pstr->mbs + byte_idx,
+ pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen);
+ pstr->wcs[byte_idx++] = wcu;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ else if (mbclen == (size_t) -1 || mbclen == 0)
+ {
+ /* It is an invalid character or '\0'. Just use the byte. */
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
+ pstr->mbs[byte_idx] = ch;
+ /* And also cast it to wide char. */
+ pstr->wcs[byte_idx++] = (wchar_t) ch;
+ if (BE (mbclen == (size_t) -1, 0))
+ pstr->cur_state = prev_st;
+ }
+ else
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = byte_idx;
+ return REG_NOERROR;
+ }
+ else
+ for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;)
+ {
+ wchar_t wc;
+ const char *p;
+ offsets_needed:
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i, ch;
+
+ for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
+ buf[i] = pstr->trans[ch];
+ }
+ p = (const char *) buf;
+ }
+ else
+ p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
+ mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state);
+ if (BE (mbclen + 2 > 2, 1))
+ {
+ wchar_t wcu = wc;
+ if (iswlower (wc))
+ {
+ size_t mbcdlen;
+
+ wcu = towupper (wc);
+ mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st);
+ if (BE (mbclen == mbcdlen, 1))
+ memcpy (pstr->mbs + byte_idx, buf, mbclen);
+ else if (mbcdlen != (size_t) -1)
+ {
+ size_t i;
+
+ if (byte_idx + mbcdlen > pstr->bufs_len)
+ {
+ pstr->cur_state = prev_st;
+ break;
+ }
+
+ if (pstr->offsets == NULL)
+ {
+ pstr->offsets = re_malloc (int, pstr->bufs_len);
+
+ if (pstr->offsets == NULL)
+ return REG_ESPACE;
+ }
+ if (!pstr->offsets_needed)
+ {
+ for (i = 0; i < (size_t) byte_idx; ++i)
+ pstr->offsets[i] = i;
+ pstr->offsets_needed = 1;
+ }
+
+ memcpy (pstr->mbs + byte_idx, buf, mbcdlen);
+ pstr->wcs[byte_idx] = wcu;
+ pstr->offsets[byte_idx] = src_idx;
+ for (i = 1; i < mbcdlen; ++i)
+ {
+ pstr->offsets[byte_idx + i]
+ = src_idx + (i < mbclen ? i : mbclen - 1);
+ pstr->wcs[byte_idx + i] = WEOF;
+ }
+ pstr->len += mbcdlen - mbclen;
+ if (pstr->raw_stop > src_idx)
+ pstr->stop += mbcdlen - mbclen;
+ end_idx = (pstr->bufs_len > pstr->len)
+ ? pstr->len : pstr->bufs_len;
+ byte_idx += mbcdlen;
+ src_idx += mbclen;
+ continue;
+ }
+ else
+ memcpy (pstr->mbs + byte_idx, p, mbclen);
+ }
+ else
+ memcpy (pstr->mbs + byte_idx, p, mbclen);
+
+ if (BE (pstr->offsets_needed != 0, 0))
+ {
+ size_t i;
+ for (i = 0; i < mbclen; ++i)
+ pstr->offsets[byte_idx + i] = src_idx + i;
+ }
+ src_idx += mbclen;
+
+ pstr->wcs[byte_idx++] = wcu;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ else if (mbclen == (size_t) -1 || mbclen == 0)
+ {
+ /* It is an invalid character or '\0'. Just use the byte. */
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx];
+
+ if (BE (pstr->trans != NULL, 0))
+ ch = pstr->trans [ch];
+ pstr->mbs[byte_idx] = ch;
+
+ if (BE (pstr->offsets_needed != 0, 0))
+ pstr->offsets[byte_idx] = src_idx;
+ ++src_idx;
+
+ /* And also cast it to wide char. */
+ pstr->wcs[byte_idx++] = (wchar_t) ch;
+ if (BE (mbclen == (size_t) -1, 0))
+ pstr->cur_state = prev_st;
+ }
+ else
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = src_idx;
+ return REG_NOERROR;
+}
+
+/* Skip characters until the index becomes greater than NEW_RAW_IDX.
+ Return the index. */
+
+static int
+re_string_skip_chars (pstr, new_raw_idx, last_wc)
+ re_string_t *pstr;
+ int new_raw_idx;
+ wint_t *last_wc;
+{
+ mbstate_t prev_st;
+ int rawbuf_idx;
+ size_t mbclen;
+ wchar_t wc = 0;
+
+ /* Skip the characters which are not necessary to check. */
+ for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len;
+ rawbuf_idx < new_raw_idx;)
+ {
+ int remain_len;
+ remain_len = pstr->len - rawbuf_idx;
+ prev_st = pstr->cur_state;
+ mbclen = mbrtowc (&wc, (const char *) pstr->raw_mbs + rawbuf_idx,
+ remain_len, &pstr->cur_state);
+ if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0))
+ {
+ /* We treat these cases as a singlebyte character. */
+ mbclen = 1;
+ pstr->cur_state = prev_st;
+ }
+ /* Then proceed the next character. */
+ rawbuf_idx += mbclen;
+ }
+ *last_wc = (wint_t) wc;
+ return rawbuf_idx;
+}
+#endif /* RE_ENABLE_I18N */
+
+/* Build the buffer PSTR->MBS, and apply the translation if we need.
+ This function is used in case of REG_ICASE. */
+
+static void
+build_upper_buffer (pstr)
+ re_string_t *pstr;
+{
+ int char_idx, end_idx;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx)
+ {
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx];
+ if (BE (pstr->trans != NULL, 0))
+ ch = pstr->trans[ch];
+ if (islower (ch))
+ pstr->mbs[char_idx] = toupper (ch);
+ else
+ pstr->mbs[char_idx] = ch;
+ }
+ pstr->valid_len = char_idx;
+ pstr->valid_raw_len = char_idx;
+}
+
+/* Apply TRANS to the buffer in PSTR. */
+
+static void
+re_string_translate_buffer (pstr)
+ re_string_t *pstr;
+{
+ int buf_idx, end_idx;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx)
+ {
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx];
+ pstr->mbs[buf_idx] = pstr->trans[ch];
+ }
+
+ pstr->valid_len = buf_idx;
+ pstr->valid_raw_len = buf_idx;
+}
+
+/* This function re-construct the buffers.
+ Concretely, convert to wide character in case of pstr->mb_cur_max > 1,
+ convert to upper case in case of REG_ICASE, apply translation. */
+
+static reg_errcode_t
+re_string_reconstruct (pstr, idx, eflags)
+ re_string_t *pstr;
+ int idx, eflags;
+{
+ int offset = idx - pstr->raw_mbs_idx;
+ if (BE (offset < 0, 0))
+ {
+ /* Reset buffer. */
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
+#endif /* RE_ENABLE_I18N */
+ pstr->len = pstr->raw_len;
+ pstr->stop = pstr->raw_stop;
+ pstr->valid_len = 0;
+ pstr->raw_mbs_idx = 0;
+ pstr->valid_raw_len = 0;
+ pstr->offsets_needed = 0;
+ pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
+ : CONTEXT_NEWLINE | CONTEXT_BEGBUF);
+ if (!pstr->mbs_allocated)
+ pstr->mbs = (unsigned char *) pstr->raw_mbs;
+ offset = idx;
+ }
+
+ if (BE (offset != 0, 1))
+ {
+ /* Are the characters which are already checked remain? */
+ if (BE (offset < pstr->valid_raw_len, 1)
+#ifdef RE_ENABLE_I18N
+ /* Handling this would enlarge the code too much.
+ Accept a slowdown in that case. */
+ && pstr->offsets_needed == 0
+#endif
+ )
+ {
+ /* Yes, move them to the front of the buffer. */
+ pstr->tip_context = re_string_context_at (pstr, offset - 1, eflags);
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ memmove (pstr->wcs, pstr->wcs + offset,
+ (pstr->valid_len - offset) * sizeof (wint_t));
+#endif /* RE_ENABLE_I18N */
+ if (BE (pstr->mbs_allocated, 0))
+ memmove (pstr->mbs, pstr->mbs + offset,
+ pstr->valid_len - offset);
+ pstr->valid_len -= offset;
+ pstr->valid_raw_len -= offset;
+#if DEBUG
+ assert (pstr->valid_len > 0);
+#endif
+ }
+ else
+ {
+ /* No, skip all characters until IDX. */
+#ifdef RE_ENABLE_I18N
+ if (BE (pstr->offsets_needed, 0))
+ {
+ pstr->len = pstr->raw_len - idx + offset;
+ pstr->stop = pstr->raw_stop - idx + offset;
+ pstr->offsets_needed = 0;
+ }
+#endif
+ pstr->valid_len = 0;
+ pstr->valid_raw_len = 0;
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ int wcs_idx;
+ wint_t wc = WEOF;
+
+ if (pstr->is_utf8)
+ {
+ const unsigned char *raw, *p, *q, *end;
+
+ /* Special case UTF-8. Multi-byte chars start with any
+ byte other than 0x80 - 0xbf. */
+ raw = pstr->raw_mbs + pstr->raw_mbs_idx;
+ end = raw + (offset - pstr->mb_cur_max);
+ for (p = raw + offset - 1; p >= end; --p)
+ if ((*p & 0xc0) != 0x80)
+ {
+ mbstate_t cur_state;
+ wchar_t wc2;
+ int mlen = raw + pstr->len - p;
+ unsigned char buf[6];
+
+ q = p;
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i = mlen < 6 ? mlen : 6;
+ while (--i >= 0)
+ buf[i] = pstr->trans[p[i]];
+ q = buf;
+ }
+ /* XXX Don't use mbrtowc, we know which conversion
+ to use (UTF-8 -> UCS4). */
+ memset (&cur_state, 0, sizeof (cur_state));
+ mlen = (mbrtowc (&wc2, (const char *) p, mlen,
+ &cur_state)
+ - (raw + offset - p));
+ if (mlen >= 0)
+ {
+ memset (&pstr->cur_state, '\0',
+ sizeof (mbstate_t));
+ pstr->valid_len = mlen;
+ wc = wc2;
+ }
+ break;
+ }
+ }
+
+ if (wc == WEOF)
+ pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx;
+ if (BE (pstr->valid_len, 0))
+ {
+ for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx)
+ pstr->wcs[wcs_idx] = WEOF;
+ if (pstr->mbs_allocated)
+ memset (pstr->mbs, 255, pstr->valid_len);
+ }
+ pstr->valid_raw_len = pstr->valid_len;
+ pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
+ && IS_WIDE_WORD_CHAR (wc))
+ ? CONTEXT_WORD
+ : ((IS_WIDE_NEWLINE (wc)
+ && pstr->newline_anchor)
+ ? CONTEXT_NEWLINE : 0));
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1];
+ if (pstr->trans)
+ c = pstr->trans[c];
+ pstr->tip_context = (bitset_contain (pstr->word_char, c)
+ ? CONTEXT_WORD
+ : ((IS_NEWLINE (c) && pstr->newline_anchor)
+ ? CONTEXT_NEWLINE : 0));
+ }
+ }
+ if (!BE (pstr->mbs_allocated, 0))
+ pstr->mbs += offset;
+ }
+ pstr->raw_mbs_idx = idx;
+ pstr->len -= offset;
+ pstr->stop -= offset;
+
+ /* Then build the buffers. */
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ if (pstr->icase)
+ {
+ int ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ else
+ build_wcs_buffer (pstr);
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ if (BE (pstr->mbs_allocated, 0))
+ {
+ if (pstr->icase)
+ build_upper_buffer (pstr);
+ else if (pstr->trans != NULL)
+ re_string_translate_buffer (pstr);
+ }
+ else
+ pstr->valid_len = pstr->len;
+
+ pstr->cur_idx = 0;
+ return REG_NOERROR;
+}
+
+static unsigned char
+re_string_peek_byte_case (pstr, idx)
+ const re_string_t *pstr;
+ int idx;
+{
+ int ch, off;
+
+ /* Handle the common (easiest) cases first. */
+ if (BE (!pstr->mbs_allocated, 1))
+ return re_string_peek_byte (pstr, idx);
+
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1
+ && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx))
+ return re_string_peek_byte (pstr, idx);
+#endif
+
+ off = pstr->cur_idx + idx;
+#ifdef RE_ENABLE_I18N
+ if (pstr->offsets_needed)
+ off = pstr->offsets[off];
+#endif
+
+ ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I
+ this function returns CAPITAL LETTER I instead of first byte of
+ DOTLESS SMALL LETTER I. The latter would confuse the parser,
+ since peek_byte_case doesn't advance cur_idx in any way. */
+ if (pstr->offsets_needed && !isascii (ch))
+ return re_string_peek_byte (pstr, idx);
+#endif
+
+ return ch;
+}
+
+static unsigned char
+re_string_fetch_byte_case (pstr)
+ re_string_t *pstr;
+{
+ if (BE (!pstr->mbs_allocated, 1))
+ return re_string_fetch_byte (pstr);
+
+#ifdef RE_ENABLE_I18N
+ if (pstr->offsets_needed)
+ {
+ int off, ch;
+
+ /* For tr_TR.UTF-8 [[:islower:]] there is
+ [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip
+ in that case the whole multi-byte character and return
+ the original letter. On the other side, with
+ [[: DOTLESS SMALL LETTER I return [[:I, as doing
+ anything else would complicate things too much. */
+
+ if (!re_string_first_byte (pstr, pstr->cur_idx))
+ return re_string_fetch_byte (pstr);
+
+ off = pstr->offsets[pstr->cur_idx];
+ ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
+
+ if (! isascii (ch))
+ return re_string_fetch_byte (pstr);
+
+ re_string_skip_bytes (pstr,
+ re_string_char_size_at (pstr, pstr->cur_idx));
+ return ch;
+ }
+#endif
+
+ return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++];
+}
+
+static void
+re_string_destruct (pstr)
+ re_string_t *pstr;
+{
+#ifdef RE_ENABLE_I18N
+ re_free (pstr->wcs);
+ re_free (pstr->offsets);
+#endif /* RE_ENABLE_I18N */
+ if (pstr->mbs_allocated)
+ re_free (pstr->mbs);
+}
+
+/* Return the context at IDX in INPUT. */
+
+static unsigned int
+re_string_context_at (input, idx, eflags)
+ const re_string_t *input;
+ int idx, eflags;
+{
+ int c;
+ if (BE (idx < 0, 0))
+ /* In this case, we use the value stored in input->tip_context,
+ since we can't know the character in input->mbs[-1] here. */
+ return input->tip_context;
+ if (BE (idx == input->len, 0))
+ return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
+ : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc;
+ int wc_idx = idx;
+ while(input->wcs[wc_idx] == WEOF)
+ {
+#ifdef DEBUG
+ /* It must not happen. */
+ assert (wc_idx >= 0);
+#endif
+ --wc_idx;
+ if (wc_idx < 0)
+ return input->tip_context;
+ }
+ wc = input->wcs[wc_idx];
+ if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc))
+ return CONTEXT_WORD;
+ return (IS_WIDE_NEWLINE (wc) && input->newline_anchor
+ ? CONTEXT_NEWLINE : 0);
+ }
+ else
+#endif
+ {
+ c = re_string_byte_at (input, idx);
+ if (bitset_contain (input->word_char, c))
+ return CONTEXT_WORD;
+ return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0;
+ }
+}
+
+/* Functions for set operation. */
+
+static reg_errcode_t
+re_node_set_alloc (set, size)
+ re_node_set *set;
+ int size;
+{
+ set->alloc = size;
+ set->nelem = 0;
+ set->elems = re_malloc (int, size);
+ if (BE (set->elems == NULL, 0))
+ return REG_ESPACE;
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+re_node_set_init_1 (set, elem)
+ re_node_set *set;
+ int elem;
+{
+ set->alloc = 1;
+ set->nelem = 1;
+ set->elems = re_malloc (int, 1);
+ if (BE (set->elems == NULL, 0))
+ {
+ set->alloc = set->nelem = 0;
+ return REG_ESPACE;
+ }
+ set->elems[0] = elem;
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+re_node_set_init_2 (set, elem1, elem2)
+ re_node_set *set;
+ int elem1, elem2;
+{
+ set->alloc = 2;
+ set->elems = re_malloc (int, 2);
+ if (BE (set->elems == NULL, 0))
+ return REG_ESPACE;
+ if (elem1 == elem2)
+ {
+ set->nelem = 1;
+ set->elems[0] = elem1;
+ }
+ else
+ {
+ set->nelem = 2;
+ if (elem1 < elem2)
+ {
+ set->elems[0] = elem1;
+ set->elems[1] = elem2;
+ }
+ else
+ {
+ set->elems[0] = elem2;
+ set->elems[1] = elem1;
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+re_node_set_init_copy (dest, src)
+ re_node_set *dest;
+ const re_node_set *src;
+{
+ dest->nelem = src->nelem;
+ if (src->nelem > 0)
+ {
+ dest->alloc = dest->nelem;
+ dest->elems = re_malloc (int, dest->alloc);
+ if (BE (dest->elems == NULL, 0))
+ {
+ dest->alloc = dest->nelem = 0;
+ return REG_ESPACE;
+ }
+ memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
+ }
+ else
+ re_node_set_init_empty (dest);
+ return REG_NOERROR;
+}
+
+/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded.
+ Note: We assume dest->elems is NULL, when dest->alloc is 0. */
+
+static reg_errcode_t
+re_node_set_add_intersect (dest, src1, src2)
+ re_node_set *dest;
+ const re_node_set *src1, *src2;
+{
+ int i1, i2, is, id, delta, sbase;
+ if (src1->nelem == 0 || src2->nelem == 0)
+ return REG_NOERROR;
+
+ /* We need dest->nelem + 2 * elems_in_intersection; this is a
+ conservative estimate. */
+ if (src1->nelem + src2->nelem + dest->nelem > dest->alloc)
+ {
+ int new_alloc = src1->nelem + src2->nelem + dest->alloc;
+ int *new_elems = re_realloc (dest->elems, int, new_alloc);
+ if (BE (new_elems == NULL, 0))
+ return REG_ESPACE;
+ dest->elems = new_elems;
+ dest->alloc = new_alloc;
+ }
+
+ /* Find the items in the intersection of SRC1 and SRC2, and copy
+ into the top of DEST those that are not already in DEST itself. */
+ sbase = dest->nelem + src1->nelem + src2->nelem;
+ i1 = src1->nelem - 1;
+ i2 = src2->nelem - 1;
+ id = dest->nelem - 1;
+ for (;;)
+ {
+ if (src1->elems[i1] == src2->elems[i2])
+ {
+ /* Try to find the item in DEST. Maybe we could binary search? */
+ while (id >= 0 && dest->elems[id] > src1->elems[i1])
+ --id;
+
+ if (id < 0 || dest->elems[id] != src1->elems[i1])
+ dest->elems[--sbase] = src1->elems[i1];
+
+ if (--i1 < 0 || --i2 < 0)
+ break;
+ }
+
+ /* Lower the highest of the two items. */
+ else if (src1->elems[i1] < src2->elems[i2])
+ {
+ if (--i2 < 0)
+ break;
+ }
+ else
+ {
+ if (--i1 < 0)
+ break;
+ }
+ }
+
+ id = dest->nelem - 1;
+ is = dest->nelem + src1->nelem + src2->nelem - 1;
+ delta = is - sbase + 1;
+
+ /* Now copy. When DELTA becomes zero, the remaining
+ DEST elements are already in place; this is more or
+ less the same loop that is in re_node_set_merge. */
+ dest->nelem += delta;
+ if (delta > 0 && id >= 0)
+ for (;;)
+ {
+ if (dest->elems[is] > dest->elems[id])
+ {
+ /* Copy from the top. */
+ dest->elems[id + delta--] = dest->elems[is--];
+ if (delta == 0)
+ break;
+ }
+ else
+ {
+ /* Slide from the bottom. */
+ dest->elems[id + delta] = dest->elems[id];
+ if (--id < 0)
+ break;
+ }
+ }
+
+ /* Copy remaining SRC elements. */
+ memcpy (dest->elems, dest->elems + sbase, delta * sizeof (int));
+
+ return REG_NOERROR;
+}
+
+/* Calculate the union set of the sets SRC1 and SRC2. And store it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
+
+static reg_errcode_t
+re_node_set_init_union (dest, src1, src2)
+ re_node_set *dest;
+ const re_node_set *src1, *src2;
+{
+ int i1, i2, id;
+ if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0)
+ {
+ dest->alloc = src1->nelem + src2->nelem;
+ dest->elems = re_malloc (int, dest->alloc);
+ if (BE (dest->elems == NULL, 0))
+ return REG_ESPACE;
+ }
+ else
+ {
+ if (src1 != NULL && src1->nelem > 0)
+ return re_node_set_init_copy (dest, src1);
+ else if (src2 != NULL && src2->nelem > 0)
+ return re_node_set_init_copy (dest, src2);
+ else
+ re_node_set_init_empty (dest);
+ return REG_NOERROR;
+ }
+ for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;)
+ {
+ if (src1->elems[i1] > src2->elems[i2])
+ {
+ dest->elems[id++] = src2->elems[i2++];
+ continue;
+ }
+ if (src1->elems[i1] == src2->elems[i2])
+ ++i2;
+ dest->elems[id++] = src1->elems[i1++];
+ }
+ if (i1 < src1->nelem)
+ {
+ memcpy (dest->elems + id, src1->elems + i1,
+ (src1->nelem - i1) * sizeof (int));
+ id += src1->nelem - i1;
+ }
+ else if (i2 < src2->nelem)
+ {
+ memcpy (dest->elems + id, src2->elems + i2,
+ (src2->nelem - i2) * sizeof (int));
+ id += src2->nelem - i2;
+ }
+ dest->nelem = id;
+ return REG_NOERROR;
+}
+
+/* Calculate the union set of the sets DEST and SRC. And store it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
+
+static reg_errcode_t
+re_node_set_merge (dest, src)
+ re_node_set *dest;
+ const re_node_set *src;
+{
+ int is, id, sbase, delta;
+ if (src == NULL || src->nelem == 0)
+ return REG_NOERROR;
+ if (dest->alloc < 2 * src->nelem + dest->nelem)
+ {
+ int new_alloc = 2 * (src->nelem + dest->alloc);
+ int *new_buffer = re_realloc (dest->elems, int, new_alloc);
+ if (BE (new_buffer == NULL, 0))
+ return REG_ESPACE;
+ dest->elems = new_buffer;
+ dest->alloc = new_alloc;
+ }
+
+ if (BE (dest->nelem == 0, 0))
+ {
+ dest->nelem = src->nelem;
+ memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
+ return REG_NOERROR;
+ }
+
+ /* Copy into the top of DEST the items of SRC that are not
+ found in DEST. Maybe we could binary search in DEST? */
+ for (sbase = dest->nelem + 2 * src->nelem,
+ is = src->nelem - 1, id = dest->nelem - 1; is >= 0 && id >= 0; )
+ {
+ if (dest->elems[id] == src->elems[is])
+ is--, id--;
+ else if (dest->elems[id] < src->elems[is])
+ dest->elems[--sbase] = src->elems[is--];
+ else /* if (dest->elems[id] > src->elems[is]) */
+ --id;
+ }
+
+ if (is >= 0)
+ {
+ /* If DEST is exhausted, the remaining items of SRC must be unique. */
+ sbase -= is + 1;
+ memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (int));
+ }
+
+ id = dest->nelem - 1;
+ is = dest->nelem + 2 * src->nelem - 1;
+ delta = is - sbase + 1;
+ if (delta == 0)
+ return REG_NOERROR;
+
+ /* Now copy. When DELTA becomes zero, the remaining
+ DEST elements are already in place. */
+ dest->nelem += delta;
+ for (;;)
+ {
+ if (dest->elems[is] > dest->elems[id])
+ {
+ /* Copy from the top. */
+ dest->elems[id + delta--] = dest->elems[is--];
+ if (delta == 0)
+ break;
+ }
+ else
+ {
+ /* Slide from the bottom. */
+ dest->elems[id + delta] = dest->elems[id];
+ if (--id < 0)
+ {
+ /* Copy remaining SRC elements. */
+ memcpy (dest->elems, dest->elems + sbase,
+ delta * sizeof (int));
+ break;
+ }
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Insert the new element ELEM to the re_node_set* SET.
+ SET should not already have ELEM.
+ return -1 if an error is occured, return 1 otherwise. */
+
+static int
+re_node_set_insert (set, elem)
+ re_node_set *set;
+ int elem;
+{
+ int idx;
+ /* In case the set is empty. */
+ if (set->alloc == 0)
+ {
+ if (BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1))
+ return 1;
+ else
+ return -1;
+ }
+
+ if (BE (set->nelem, 0) == 0)
+ {
+ /* We already guaranteed above that set->alloc != 0. */
+ set->elems[0] = elem;
+ ++set->nelem;
+ return 1;
+ }
+
+ /* Realloc if we need. */
+ if (set->alloc == set->nelem)
+ {
+ int *new_array;
+ set->alloc = set->alloc * 2;
+ new_array = re_realloc (set->elems, int, set->alloc);
+ if (BE (new_array == NULL, 0))
+ return -1;
+ set->elems = new_array;
+ }
+
+ /* Move the elements which follows the new element. Test the
+ first element separately to skip a check in the inner loop. */
+ if (elem < set->elems[0])
+ {
+ idx = 0;
+ for (idx = set->nelem; idx > 0; idx--)
+ set->elems[idx] = set->elems[idx - 1];
+ }
+ else
+ {
+ for (idx = set->nelem; set->elems[idx - 1] > elem; idx--)
+ set->elems[idx] = set->elems[idx - 1];
+ }
+
+ /* Insert the new element. */
+ set->elems[idx] = elem;
+ ++set->nelem;
+ return 1;
+}
+
+/* Insert the new element ELEM to the re_node_set* SET.
+ SET should not already have any element greater than or equal to ELEM.
+ Return -1 if an error is occured, return 1 otherwise. */
+
+static int
+re_node_set_insert_last (set, elem)
+ re_node_set *set;
+ int elem;
+{
+ /* Realloc if we need. */
+ if (set->alloc == set->nelem)
+ {
+ int *new_array;
+ set->alloc = (set->alloc + 1) * 2;
+ new_array = re_realloc (set->elems, int, set->alloc);
+ if (BE (new_array == NULL, 0))
+ return -1;
+ set->elems = new_array;
+ }
+
+ /* Insert the new element. */
+ set->elems[set->nelem++] = elem;
+ return 1;
+}
+
+/* Compare two node sets SET1 and SET2.
+ return 1 if SET1 and SET2 are equivalent, return 0 otherwise. */
+
+static int
+re_node_set_compare (set1, set2)
+ const re_node_set *set1, *set2;
+{
+ int i;
+ if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem)
+ return 0;
+ for (i = set1->nelem ; --i >= 0 ; )
+ if (set1->elems[i] != set2->elems[i])
+ return 0;
+ return 1;
+}
+
+/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */
+
+static int
+re_node_set_contains (set, elem)
+ const re_node_set *set;
+ int elem;
+{
+ unsigned int idx, right, mid;
+ if (set->nelem <= 0)
+ return 0;
+
+ /* Binary search the element. */
+ idx = 0;
+ right = set->nelem - 1;
+ while (idx < right)
+ {
+ mid = (idx + right) / 2;
+ if (set->elems[mid] < elem)
+ idx = mid + 1;
+ else
+ right = mid;
+ }
+ return set->elems[idx] == elem ? idx + 1 : 0;
+}
+
+static void
+re_node_set_remove_at (set, idx)
+ re_node_set *set;
+ int idx;
+{
+ if (idx < 0 || idx >= set->nelem)
+ return;
+ --set->nelem;
+ for (; idx < set->nelem; idx++)
+ set->elems[idx] = set->elems[idx + 1];
+}
+
+
+/* Add the token TOKEN to dfa->nodes, and return the index of the token.
+ Or return -1, if an error will be occured. */
+
+static int
+re_dfa_add_node (dfa, token)
+ re_dfa_t *dfa;
+ re_token_t token;
+{
+ int type = token.type;
+ if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0))
+ {
+ int new_nodes_alloc = dfa->nodes_alloc * 2;
+ int *new_nexts, *new_indices;
+ re_node_set *new_edests, *new_eclosures;
+
+ re_token_t *new_array = re_realloc (dfa->nodes, re_token_t,
+ new_nodes_alloc);
+ if (BE (new_array == NULL, 0))
+ return -1;
+ dfa->nodes = new_array;
+ new_nexts = re_realloc (dfa->nexts, int, new_nodes_alloc);
+ new_indices = re_realloc (dfa->org_indices, int, new_nodes_alloc);
+ new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc);
+ new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc);
+ if (BE (new_nexts == NULL || new_indices == NULL
+ || new_edests == NULL || new_eclosures == NULL, 0))
+ return -1;
+ dfa->nexts = new_nexts;
+ dfa->org_indices = new_indices;
+ dfa->edests = new_edests;
+ dfa->eclosures = new_eclosures;
+ dfa->nodes_alloc = new_nodes_alloc;
+ }
+ dfa->nodes[dfa->nodes_len] = token;
+ dfa->nodes[dfa->nodes_len].constraint = 0;
+#ifdef RE_ENABLE_I18N
+ dfa->nodes[dfa->nodes_len].accept_mb =
+ (type == OP_PERIOD && dfa->mb_cur_max > 1) || type == COMPLEX_BRACKET;
+#endif
+ dfa->nexts[dfa->nodes_len] = -1;
+ re_node_set_init_empty (dfa->edests + dfa->nodes_len);
+ re_node_set_init_empty (dfa->eclosures + dfa->nodes_len);
+ return dfa->nodes_len++;
+}
+
+static unsigned int inline
+calc_state_hash (nodes, context)
+ const re_node_set *nodes;
+ unsigned int context;
+{
+ unsigned int hash = nodes->nelem + context;
+ int i;
+ for (i = 0 ; i < nodes->nelem ; i++)
+ hash += nodes->elems[i];
+ return hash;
+}
+
+/* Search for the state whose node_set is equivalent to NODES.
+ Return the pointer to the state, if we found it in the DFA.
+ Otherwise create the new one and return it. In case of an error
+ return NULL and set the error code in ERR.
+ Note: - We assume NULL as the invalid state, then it is possible that
+ return value is NULL and ERR is REG_NOERROR.
+ - We never return non-NULL value in case of any errors, it is for
+ optimization. */
+
+static re_dfastate_t*
+re_acquire_state (err, dfa, nodes)
+ reg_errcode_t *err;
+ re_dfa_t *dfa;
+ const re_node_set *nodes;
+{
+ unsigned int hash;
+ re_dfastate_t *new_state;
+ struct re_state_table_entry *spot;
+ int i;
+ if (BE (nodes->nelem == 0, 0))
+ {
+ *err = REG_NOERROR;
+ return NULL;
+ }
+ hash = calc_state_hash (nodes, 0);
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+
+ for (i = 0 ; i < spot->num ; i++)
+ {
+ re_dfastate_t *state = spot->array[i];
+ if (hash != state->hash)
+ continue;
+ if (re_node_set_compare (&state->nodes, nodes))
+ return state;
+ }
+
+ /* There are no appropriate state in the dfa, create the new one. */
+ new_state = create_ci_newstate (dfa, nodes, hash);
+ if (BE (new_state != NULL, 1))
+ return new_state;
+ else
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+}
+
+/* Search for the state whose node_set is equivalent to NODES and
+ whose context is equivalent to CONTEXT.
+ Return the pointer to the state, if we found it in the DFA.
+ Otherwise create the new one and return it. In case of an error
+ return NULL and set the error code in ERR.
+ Note: - We assume NULL as the invalid state, then it is possible that
+ return value is NULL and ERR is REG_NOERROR.
+ - We never return non-NULL value in case of any errors, it is for
+ optimization. */
+
+static re_dfastate_t*
+re_acquire_state_context (err, dfa, nodes, context)
+ reg_errcode_t *err;
+ re_dfa_t *dfa;
+ const re_node_set *nodes;
+ unsigned int context;
+{
+ unsigned int hash;
+ re_dfastate_t *new_state;
+ struct re_state_table_entry *spot;
+ int i;
+ if (nodes->nelem == 0)
+ {
+ *err = REG_NOERROR;
+ return NULL;
+ }
+ hash = calc_state_hash (nodes, context);
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+
+ for (i = 0 ; i < spot->num ; i++)
+ {
+ re_dfastate_t *state = spot->array[i];
+ if (state->hash == hash
+ && state->context == context
+ && re_node_set_compare (state->entrance_nodes, nodes))
+ return state;
+ }
+ /* There are no appropriate state in `dfa', create the new one. */
+ new_state = create_cd_newstate (dfa, nodes, context, hash);
+ if (BE (new_state != NULL, 1))
+ return new_state;
+ else
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+}
+
+/* Finish initialization of the new state NEWSTATE, and using its hash value
+ HASH put in the appropriate bucket of DFA's state table. Return value
+ indicates the error code if failed. */
+
+static reg_errcode_t
+register_state (dfa, newstate, hash)
+ re_dfa_t *dfa;
+ re_dfastate_t *newstate;
+ unsigned int hash;
+{
+ struct re_state_table_entry *spot;
+ reg_errcode_t err;
+ int i;
+
+ newstate->hash = hash;
+ err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return REG_ESPACE;
+ for (i = 0; i < newstate->nodes.nelem; i++)
+ {
+ int elem = newstate->nodes.elems[i];
+ if (!IS_EPSILON_NODE (dfa->nodes[elem].type))
+ re_node_set_insert_last (&newstate->non_eps_nodes, elem);
+ }
+
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+ if (BE (spot->alloc <= spot->num, 0))
+ {
+ int new_alloc = 2 * spot->num + 2;
+ re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *,
+ new_alloc);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ spot->array = new_array;
+ spot->alloc = new_alloc;
+ }
+ spot->array[spot->num++] = newstate;
+ return REG_NOERROR;
+}
+
+/* Create the new state which is independ of contexts.
+ Return the new state if succeeded, otherwise return NULL. */
+
+static re_dfastate_t *
+create_ci_newstate (dfa, nodes, hash)
+ re_dfa_t *dfa;
+ const re_node_set *nodes;
+ unsigned int hash;
+{
+ int i;
+ reg_errcode_t err;
+ re_dfastate_t *newstate;
+
+ newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
+ if (BE (newstate == NULL, 0))
+ return NULL;
+ err = re_node_set_init_copy (&newstate->nodes, nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_free (newstate);
+ return NULL;
+ }
+
+ newstate->entrance_nodes = &newstate->nodes;
+ for (i = 0 ; i < nodes->nelem ; i++)
+ {
+ re_token_t *node = dfa->nodes + nodes->elems[i];
+ re_token_type_t type = node->type;
+ if (type == CHARACTER && !node->constraint)
+ continue;
+#ifdef RE_ENABLE_I18N
+ newstate->accept_mb |= node->accept_mb;
+#endif /* RE_ENABLE_I18N */
+
+ /* If the state has the halt node, the state is a halt state. */
+ if (type == END_OF_RE)
+ newstate->halt = 1;
+ else if (type == OP_BACK_REF)
+ newstate->has_backref = 1;
+ else if (type == ANCHOR || node->constraint)
+ newstate->has_constraint = 1;
+ }
+ err = register_state (dfa, newstate, hash);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_state (newstate);
+ newstate = NULL;
+ }
+ return newstate;
+}
+
+/* Create the new state which is depend on the context CONTEXT.
+ Return the new state if succeeded, otherwise return NULL. */
+
+static re_dfastate_t *
+create_cd_newstate (dfa, nodes, context, hash)
+ re_dfa_t *dfa;
+ const re_node_set *nodes;
+ unsigned int context, hash;
+{
+ int i, nctx_nodes = 0;
+ reg_errcode_t err;
+ re_dfastate_t *newstate;
+
+ newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
+ if (BE (newstate == NULL, 0))
+ return NULL;
+ err = re_node_set_init_copy (&newstate->nodes, nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_free (newstate);
+ return NULL;
+ }
+
+ newstate->context = context;
+ newstate->entrance_nodes = &newstate->nodes;
+
+ for (i = 0 ; i < nodes->nelem ; i++)
+ {
+ unsigned int constraint = 0;
+ re_token_t *node = dfa->nodes + nodes->elems[i];
+ re_token_type_t type = node->type;
+ if (node->constraint)
+ constraint = node->constraint;
+
+ if (type == CHARACTER && !constraint)
+ continue;
+#ifdef RE_ENABLE_I18N
+ newstate->accept_mb |= node->accept_mb;
+#endif /* RE_ENABLE_I18N */
+
+ /* If the state has the halt node, the state is a halt state. */
+ if (type == END_OF_RE)
+ newstate->halt = 1;
+ else if (type == OP_BACK_REF)
+ newstate->has_backref = 1;
+ else if (type == ANCHOR)
+ constraint = node->opr.ctx_type;
+
+ if (constraint)
+ {
+ if (newstate->entrance_nodes == &newstate->nodes)
+ {
+ newstate->entrance_nodes = re_malloc (re_node_set, 1);
+ if (BE (newstate->entrance_nodes == NULL, 0))
+ {
+ free_state (newstate);
+ return NULL;
+ }
+ re_node_set_init_copy (newstate->entrance_nodes, nodes);
+ nctx_nodes = 0;
+ newstate->has_constraint = 1;
+ }
+
+ if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context))
+ {
+ re_node_set_remove_at (&newstate->nodes, i - nctx_nodes);
+ ++nctx_nodes;
+ }
+ }
+ }
+ err = register_state (dfa, newstate, hash);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_state (newstate);
+ newstate = NULL;
+ }
+ return newstate;
+}
+
+static void
+free_state (state)
+ re_dfastate_t *state;
+{
+ re_node_set_free (&state->non_eps_nodes);
+ re_node_set_free (&state->inveclosure);
+ if (state->entrance_nodes != &state->nodes)
+ {
+ re_node_set_free (state->entrance_nodes);
+ re_free (state->entrance_nodes);
+ }
+ re_node_set_free (&state->nodes);
+ re_free (state->word_trtable);
+ re_free (state->trtable);
+ re_free (state);
+}
diff --git a/gnu/lib/libregex/regex_internal.h b/gnu/lib/libregex/regex_internal.h
new file mode 100644
index 0000000..58fa749
--- /dev/null
+++ b/gnu/lib/libregex/regex_internal.h
@@ -0,0 +1,798 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _REGEX_INTERNAL_H
+#define _REGEX_INTERNAL_H 1
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC
+# include <langinfo.h>
+#endif
+#if defined HAVE_LOCALE_H || defined _LIBC
+# include <locale.h>
+#endif
+#if defined HAVE_WCHAR_H || defined _LIBC
+# include <wchar.h>
+#endif /* HAVE_WCHAR_H || _LIBC */
+#if defined HAVE_WCTYPE_H || defined _LIBC
+# include <wctype.h>
+#endif /* HAVE_WCTYPE_H || _LIBC */
+
+/* In case that the system doesn't have isblank(). */
+#if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank
+# define isblank(ch) ((ch) == ' ' || (ch) == '\t')
+#endif
+
+#ifdef _LIBC
+# ifndef _RE_DEFINE_LOCALE_FUNCTIONS
+# define _RE_DEFINE_LOCALE_FUNCTIONS 1
+# include <locale/localeinfo.h>
+# include <locale/elem-hash.h>
+# include <locale/coll-lookup.h>
+# endif
+#endif
+
+/* This is for other GNU distributions with internationalized messages. */
+#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
+# include <libintl.h>
+# ifdef _LIBC
+# undef gettext
+# define gettext(msgid) \
+ INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES)
+# endif
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef gettext_noop
+/* This define is so xgettext can find the internationalizable
+ strings. */
+# define gettext_noop(String) String
+#endif
+
+#if (defined MB_CUR_MAX && HAVE_LOCALE_H && HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_WCRTOMB && HAVE_MBRTOWC && HAVE_WCSCOLL) || _LIBC
+# define RE_ENABLE_I18N
+#endif
+
+#if __GNUC__ >= 3
+# define BE(expr, val) __builtin_expect (expr, val)
+#else
+# define BE(expr, val) (expr)
+# define inline
+#endif
+
+/* Number of bits in a byte. */
+#define BYTE_BITS 8
+/* Number of single byte character. */
+#define SBC_MAX 256
+
+#define COLL_ELEM_LEN_MAX 8
+
+/* The character which represents newline. */
+#define NEWLINE_CHAR '\n'
+#define WIDE_NEWLINE_CHAR L'\n'
+
+/* Rename to standard API for using out of glibc. */
+#ifndef _LIBC
+# define __wctype wctype
+# define __iswctype iswctype
+# define __btowc btowc
+# define __mempcpy mempcpy
+# define __wcrtomb wcrtomb
+# define __regfree regfree
+# define attribute_hidden
+#endif /* not _LIBC */
+
+#ifdef __GNUC__
+# define __attribute(arg) __attribute__ (arg)
+#else
+# define __attribute(arg)
+#endif
+
+extern const char __re_error_msgid[] attribute_hidden;
+extern const size_t __re_error_msgid_idx[] attribute_hidden;
+
+/* Number of bits in an unsinged int. */
+#define UINT_BITS (sizeof (unsigned int) * BYTE_BITS)
+/* Number of unsigned int in an bit_set. */
+#define BITSET_UINTS ((SBC_MAX + UINT_BITS - 1) / UINT_BITS)
+typedef unsigned int bitset[BITSET_UINTS];
+typedef unsigned int *re_bitset_ptr_t;
+typedef const unsigned int *re_const_bitset_ptr_t;
+
+#define bitset_set(set,i) (set[i / UINT_BITS] |= 1 << i % UINT_BITS)
+#define bitset_clear(set,i) (set[i / UINT_BITS] &= ~(1 << i % UINT_BITS))
+#define bitset_contain(set,i) (set[i / UINT_BITS] & (1 << i % UINT_BITS))
+#define bitset_empty(set) memset (set, 0, sizeof (unsigned int) * BITSET_UINTS)
+#define bitset_set_all(set) \
+ memset (set, 255, sizeof (unsigned int) * BITSET_UINTS)
+#define bitset_copy(dest,src) \
+ memcpy (dest, src, sizeof (unsigned int) * BITSET_UINTS)
+static inline void bitset_not (bitset set);
+static inline void bitset_merge (bitset dest, const bitset src);
+static inline void bitset_not_merge (bitset dest, const bitset src);
+static inline void bitset_mask (bitset dest, const bitset src);
+
+#define PREV_WORD_CONSTRAINT 0x0001
+#define PREV_NOTWORD_CONSTRAINT 0x0002
+#define NEXT_WORD_CONSTRAINT 0x0004
+#define NEXT_NOTWORD_CONSTRAINT 0x0008
+#define PREV_NEWLINE_CONSTRAINT 0x0010
+#define NEXT_NEWLINE_CONSTRAINT 0x0020
+#define PREV_BEGBUF_CONSTRAINT 0x0040
+#define NEXT_ENDBUF_CONSTRAINT 0x0080
+#define WORD_DELIM_CONSTRAINT 0x0100
+#define NOT_WORD_DELIM_CONSTRAINT 0x0200
+
+typedef enum
+{
+ INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
+ WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
+ WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
+ INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
+ LINE_FIRST = PREV_NEWLINE_CONSTRAINT,
+ LINE_LAST = NEXT_NEWLINE_CONSTRAINT,
+ BUF_FIRST = PREV_BEGBUF_CONSTRAINT,
+ BUF_LAST = NEXT_ENDBUF_CONSTRAINT,
+ WORD_DELIM = WORD_DELIM_CONSTRAINT,
+ NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT
+} re_context_type;
+
+typedef struct
+{
+ int alloc;
+ int nelem;
+ int *elems;
+} re_node_set;
+
+typedef enum
+{
+ NON_TYPE = 0,
+
+ /* Node type, These are used by token, node, tree. */
+ CHARACTER = 1,
+ END_OF_RE = 2,
+ SIMPLE_BRACKET = 3,
+ OP_BACK_REF = 4,
+ OP_PERIOD = 5,
+#ifdef RE_ENABLE_I18N
+ COMPLEX_BRACKET = 6,
+ OP_UTF8_PERIOD = 7,
+#endif /* RE_ENABLE_I18N */
+
+ /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used
+ when the debugger shows values of this enum type. */
+#define EPSILON_BIT 8
+ OP_OPEN_SUBEXP = EPSILON_BIT | 0,
+ OP_CLOSE_SUBEXP = EPSILON_BIT | 1,
+ OP_ALT = EPSILON_BIT | 2,
+ OP_DUP_ASTERISK = EPSILON_BIT | 3,
+ ANCHOR = EPSILON_BIT | 4,
+
+ /* Tree type, these are used only by tree. */
+ CONCAT = 16,
+ SUBEXP = 17,
+
+ /* Token type, these are used only by token. */
+ OP_DUP_PLUS = 18,
+ OP_DUP_QUESTION,
+ OP_OPEN_BRACKET,
+ OP_CLOSE_BRACKET,
+ OP_CHARSET_RANGE,
+ OP_OPEN_DUP_NUM,
+ OP_CLOSE_DUP_NUM,
+ OP_NON_MATCH_LIST,
+ OP_OPEN_COLL_ELEM,
+ OP_CLOSE_COLL_ELEM,
+ OP_OPEN_EQUIV_CLASS,
+ OP_CLOSE_EQUIV_CLASS,
+ OP_OPEN_CHAR_CLASS,
+ OP_CLOSE_CHAR_CLASS,
+ OP_WORD,
+ OP_NOTWORD,
+ OP_SPACE,
+ OP_NOTSPACE,
+ BACK_SLASH
+
+} re_token_type_t;
+
+#ifdef RE_ENABLE_I18N
+typedef struct
+{
+ /* Multibyte characters. */
+ wchar_t *mbchars;
+
+ /* Collating symbols. */
+# ifdef _LIBC
+ int32_t *coll_syms;
+# endif
+
+ /* Equivalence classes. */
+# ifdef _LIBC
+ int32_t *equiv_classes;
+# endif
+
+ /* Range expressions. */
+# ifdef _LIBC
+ uint32_t *range_starts;
+ uint32_t *range_ends;
+# else /* not _LIBC */
+ wchar_t *range_starts;
+ wchar_t *range_ends;
+# endif /* not _LIBC */
+
+ /* Character classes. */
+ wctype_t *char_classes;
+
+ /* If this character set is the non-matching list. */
+ unsigned int non_match : 1;
+
+ /* # of multibyte characters. */
+ int nmbchars;
+
+ /* # of collating symbols. */
+ int ncoll_syms;
+
+ /* # of equivalence classes. */
+ int nequiv_classes;
+
+ /* # of range expressions. */
+ int nranges;
+
+ /* # of character classes. */
+ int nchar_classes;
+} re_charset_t;
+#endif /* RE_ENABLE_I18N */
+
+typedef struct
+{
+ union
+ {
+ unsigned char c; /* for CHARACTER */
+ re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset; /* for COMPLEX_BRACKET */
+#endif /* RE_ENABLE_I18N */
+ int idx; /* for BACK_REF */
+ re_context_type ctx_type; /* for ANCHOR */
+ } opr;
+#if __GNUC__ >= 2
+ re_token_type_t type : 8;
+#else
+ re_token_type_t type;
+#endif
+ unsigned int constraint : 10; /* context constraint */
+ unsigned int duplicated : 1;
+ unsigned int opt_subexp : 1;
+#ifdef RE_ENABLE_I18N
+ unsigned int accept_mb : 1;
+ /* These 2 bits can be moved into the union if needed (e.g. if running out
+ of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */
+ unsigned int mb_partial : 1;
+#endif
+ unsigned int word_char : 1;
+} re_token_t;
+
+#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT)
+
+struct re_string_t
+{
+ /* Indicate the raw buffer which is the original string passed as an
+ argument of regexec(), re_search(), etc.. */
+ const unsigned char *raw_mbs;
+ /* Store the multibyte string. In case of "case insensitive mode" like
+ REG_ICASE, upper cases of the string are stored, otherwise MBS points
+ the same address that RAW_MBS points. */
+ unsigned char *mbs;
+#ifdef RE_ENABLE_I18N
+ /* Store the wide character string which is corresponding to MBS. */
+ wint_t *wcs;
+ int *offsets;
+ mbstate_t cur_state;
+#endif
+ /* Index in RAW_MBS. Each character mbs[i] corresponds to
+ raw_mbs[raw_mbs_idx + i]. */
+ int raw_mbs_idx;
+ /* The length of the valid characters in the buffers. */
+ int valid_len;
+ /* The corresponding number of bytes in raw_mbs array. */
+ int valid_raw_len;
+ /* The length of the buffers MBS and WCS. */
+ int bufs_len;
+ /* The index in MBS, which is updated by re_string_fetch_byte. */
+ int cur_idx;
+ /* length of RAW_MBS array. */
+ int raw_len;
+ /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */
+ int len;
+ /* End of the buffer may be shorter than its length in the cases such
+ as re_match_2, re_search_2. Then, we use STOP for end of the buffer
+ instead of LEN. */
+ int raw_stop;
+ /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */
+ int stop;
+
+ /* The context of mbs[0]. We store the context independently, since
+ the context of mbs[0] may be different from raw_mbs[0], which is
+ the beginning of the input string. */
+ unsigned int tip_context;
+ /* The translation passed as a part of an argument of re_compile_pattern. */
+ unsigned RE_TRANSLATE_TYPE trans;
+ /* Copy of re_dfa_t's word_char. */
+ re_const_bitset_ptr_t word_char;
+ /* 1 if REG_ICASE. */
+ unsigned char icase;
+ unsigned char is_utf8;
+ unsigned char map_notascii;
+ unsigned char mbs_allocated;
+ unsigned char offsets_needed;
+ unsigned char newline_anchor;
+ unsigned char word_ops_used;
+ int mb_cur_max;
+};
+typedef struct re_string_t re_string_t;
+
+
+struct re_dfa_t;
+typedef struct re_dfa_t re_dfa_t;
+
+#ifndef _LIBC
+# ifdef __i386__
+# define internal_function __attribute ((regparm (3), stdcall))
+# else
+# define internal_function
+# endif
+#endif
+
+#ifndef RE_NO_INTERNAL_PROTOTYPES
+static reg_errcode_t re_string_allocate (re_string_t *pstr, const char *str,
+ int len, int init_len,
+ RE_TRANSLATE_TYPE trans, int icase,
+ const re_dfa_t *dfa)
+ internal_function;
+static reg_errcode_t re_string_construct (re_string_t *pstr, const char *str,
+ int len, RE_TRANSLATE_TYPE trans,
+ int icase, const re_dfa_t *dfa)
+ internal_function;
+static reg_errcode_t re_string_reconstruct (re_string_t *pstr, int idx,
+ int eflags) internal_function;
+static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr,
+ int new_buf_len)
+ internal_function;
+# ifdef RE_ENABLE_I18N
+static void build_wcs_buffer (re_string_t *pstr) internal_function;
+static int build_wcs_upper_buffer (re_string_t *pstr) internal_function;
+# endif /* RE_ENABLE_I18N */
+static void build_upper_buffer (re_string_t *pstr) internal_function;
+static void re_string_translate_buffer (re_string_t *pstr) internal_function;
+static void re_string_destruct (re_string_t *pstr) internal_function;
+# ifdef RE_ENABLE_I18N
+static int re_string_elem_size_at (const re_string_t *pstr, int idx)
+ internal_function __attribute ((pure));
+static inline int re_string_char_size_at (const re_string_t *pstr, int idx)
+ internal_function __attribute ((pure));
+static inline wint_t re_string_wchar_at (const re_string_t *pstr, int idx)
+ internal_function __attribute ((pure));
+# endif /* RE_ENABLE_I18N */
+static unsigned int re_string_context_at (const re_string_t *input, int idx,
+ int eflags)
+ internal_function __attribute ((pure));
+static unsigned char re_string_peek_byte_case (const re_string_t *pstr,
+ int idx)
+ internal_function __attribute ((pure));
+static unsigned char re_string_fetch_byte_case (re_string_t *pstr)
+ internal_function __attribute ((pure));
+#endif
+#define re_string_peek_byte(pstr, offset) \
+ ((pstr)->mbs[(pstr)->cur_idx + offset])
+#define re_string_fetch_byte(pstr) \
+ ((pstr)->mbs[(pstr)->cur_idx++])
+#define re_string_first_byte(pstr, idx) \
+ ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF)
+#define re_string_is_single_byte_char(pstr, idx) \
+ ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \
+ || (pstr)->wcs[(idx) + 1] != WEOF))
+#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx)
+#define re_string_cur_idx(pstr) ((pstr)->cur_idx)
+#define re_string_get_buffer(pstr) ((pstr)->mbs)
+#define re_string_length(pstr) ((pstr)->len)
+#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx])
+#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx))
+#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx))
+
+#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t)))
+#define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t)))
+#define re_free(p) free (p)
+
+struct bin_tree_t
+{
+ struct bin_tree_t *parent;
+ struct bin_tree_t *left;
+ struct bin_tree_t *right;
+ struct bin_tree_t *first;
+ struct bin_tree_t *next;
+
+ re_token_t token;
+
+ /* `node_idx' is the index in dfa->nodes, if `type' == 0.
+ Otherwise `type' indicate the type of this node. */
+ int node_idx;
+};
+typedef struct bin_tree_t bin_tree_t;
+
+#define BIN_TREE_STORAGE_SIZE \
+ ((1024 - sizeof (void *)) / sizeof (bin_tree_t))
+
+struct bin_tree_storage_t
+{
+ struct bin_tree_storage_t *next;
+ bin_tree_t data[BIN_TREE_STORAGE_SIZE];
+};
+typedef struct bin_tree_storage_t bin_tree_storage_t;
+
+#define CONTEXT_WORD 1
+#define CONTEXT_NEWLINE (CONTEXT_WORD << 1)
+#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1)
+#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1)
+
+#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD)
+#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE)
+#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF)
+#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF)
+#define IS_ORDINARY_CONTEXT(c) ((c) == 0)
+
+#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_')
+#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR)
+#define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_')
+#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR)
+
+#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \
+ ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
+ || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
+ || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\
+ || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context)))
+
+#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \
+ ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
+ || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
+ || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \
+ || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context)))
+
+struct re_dfastate_t
+{
+ unsigned int hash;
+ re_node_set nodes;
+ re_node_set non_eps_nodes;
+ re_node_set inveclosure;
+ re_node_set *entrance_nodes;
+ struct re_dfastate_t **trtable, **word_trtable;
+ unsigned int context : 4;
+ unsigned int halt : 1;
+ /* If this state can accept `multi byte'.
+ Note that we refer to multibyte characters, and multi character
+ collating elements as `multi byte'. */
+ unsigned int accept_mb : 1;
+ /* If this state has backreference node(s). */
+ unsigned int has_backref : 1;
+ unsigned int has_constraint : 1;
+};
+typedef struct re_dfastate_t re_dfastate_t;
+
+struct re_state_table_entry
+{
+ int num;
+ int alloc;
+ re_dfastate_t **array;
+};
+
+/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */
+
+typedef struct
+{
+ int next_idx;
+ int alloc;
+ re_dfastate_t **array;
+} state_array_t;
+
+/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */
+
+typedef struct
+{
+ int node;
+ int str_idx; /* The position NODE match at. */
+ state_array_t path;
+} re_sub_match_last_t;
+
+/* Store information about the node NODE whose type is OP_OPEN_SUBEXP.
+ And information about the node, whose type is OP_CLOSE_SUBEXP,
+ corresponding to NODE is stored in LASTS. */
+
+typedef struct
+{
+ int str_idx;
+ int node;
+ int next_last_offset;
+ state_array_t *path;
+ int alasts; /* Allocation size of LASTS. */
+ int nlasts; /* The number of LASTS. */
+ re_sub_match_last_t **lasts;
+} re_sub_match_top_t;
+
+struct re_backref_cache_entry
+{
+ int node;
+ int str_idx;
+ int subexp_from;
+ int subexp_to;
+ char more;
+ char unused;
+ unsigned short int eps_reachable_subexps_map;
+};
+
+typedef struct
+{
+ /* The string object corresponding to the input string. */
+ re_string_t input;
+#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+ re_dfa_t *const dfa;
+#else
+ re_dfa_t *dfa;
+#endif
+ /* EFLAGS of the argument of regexec. */
+ int eflags;
+ /* Where the matching ends. */
+ int match_last;
+ int last_node;
+ /* The state log used by the matcher. */
+ re_dfastate_t **state_log;
+ int state_log_top;
+ /* Back reference cache. */
+ int nbkref_ents;
+ int abkref_ents;
+ struct re_backref_cache_entry *bkref_ents;
+ int max_mb_elem_len;
+ int nsub_tops;
+ int asub_tops;
+ re_sub_match_top_t **sub_tops;
+} re_match_context_t;
+
+typedef struct
+{
+ re_dfastate_t **sifted_states;
+ re_dfastate_t **limited_states;
+ int last_node;
+ int last_str_idx;
+ re_node_set limits;
+} re_sift_context_t;
+
+struct re_fail_stack_ent_t
+{
+ int idx;
+ int node;
+ regmatch_t *regs;
+ re_node_set eps_via_nodes;
+};
+
+struct re_fail_stack_t
+{
+ int num;
+ int alloc;
+ struct re_fail_stack_ent_t *stack;
+};
+
+struct re_dfa_t
+{
+ re_token_t *nodes;
+ int nodes_alloc;
+ int nodes_len;
+ int *nexts;
+ int *org_indices;
+ re_node_set *edests;
+ re_node_set *eclosures;
+ re_node_set *inveclosures;
+ struct re_state_table_entry *state_table;
+ re_dfastate_t *init_state;
+ re_dfastate_t *init_state_word;
+ re_dfastate_t *init_state_nl;
+ re_dfastate_t *init_state_begbuf;
+ bin_tree_t *str_tree;
+ bin_tree_storage_t *str_tree_storage;
+ re_bitset_ptr_t sb_char;
+ int str_tree_storage_idx;
+
+ /* number of subexpressions `re_nsub' is in regex_t. */
+ unsigned int state_hash_mask;
+ int states_alloc;
+ int init_node;
+ int nbackref; /* The number of backreference in this dfa. */
+
+ /* Bitmap expressing which backreference is used. */
+ unsigned int used_bkref_map;
+ unsigned int completed_bkref_map;
+
+ unsigned int has_plural_match : 1;
+ /* If this dfa has "multibyte node", which is a backreference or
+ a node which can accept multibyte character or multi character
+ collating element. */
+ unsigned int has_mb_node : 1;
+ unsigned int is_utf8 : 1;
+ unsigned int map_notascii : 1;
+ unsigned int word_ops_used : 1;
+ int mb_cur_max;
+ bitset word_char;
+ reg_syntax_t syntax;
+ int *subexp_map;
+#ifdef DEBUG
+ char* re_str;
+#endif
+};
+
+#ifndef RE_NO_INTERNAL_PROTOTYPES
+static reg_errcode_t re_node_set_alloc (re_node_set *set, int size) internal_function;
+static reg_errcode_t re_node_set_init_1 (re_node_set *set, int elem) internal_function;
+static reg_errcode_t re_node_set_init_2 (re_node_set *set, int elem1,
+ int elem2) internal_function;
+#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set))
+static reg_errcode_t re_node_set_init_copy (re_node_set *dest,
+ const re_node_set *src) internal_function;
+static reg_errcode_t re_node_set_add_intersect (re_node_set *dest,
+ const re_node_set *src1,
+ const re_node_set *src2) internal_function;
+static reg_errcode_t re_node_set_init_union (re_node_set *dest,
+ const re_node_set *src1,
+ const re_node_set *src2) internal_function;
+static reg_errcode_t re_node_set_merge (re_node_set *dest,
+ const re_node_set *src) internal_function;
+static int re_node_set_insert (re_node_set *set, int elem) internal_function;
+static int re_node_set_insert_last (re_node_set *set,
+ int elem) internal_function;
+static int re_node_set_compare (const re_node_set *set1,
+ const re_node_set *set2)
+ internal_function __attribute ((pure));
+static int re_node_set_contains (const re_node_set *set, int elem)
+ internal_function __attribute ((pure));
+static void re_node_set_remove_at (re_node_set *set, int idx) internal_function;
+#define re_node_set_remove(set,id) \
+ (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1))
+#define re_node_set_empty(p) ((p)->nelem = 0)
+#define re_node_set_free(set) re_free ((set)->elems)
+static int re_dfa_add_node (re_dfa_t *dfa, re_token_t token) internal_function;
+static re_dfastate_t *re_acquire_state (reg_errcode_t *err, re_dfa_t *dfa,
+ const re_node_set *nodes) internal_function;
+static re_dfastate_t *re_acquire_state_context (reg_errcode_t *err,
+ re_dfa_t *dfa,
+ const re_node_set *nodes,
+ unsigned int context) internal_function;
+static void free_state (re_dfastate_t *state) internal_function;
+#endif
+
+
+typedef enum
+{
+ SB_CHAR,
+ MB_CHAR,
+ EQUIV_CLASS,
+ COLL_SYM,
+ CHAR_CLASS
+} bracket_elem_type;
+
+typedef struct
+{
+ bracket_elem_type type;
+ union
+ {
+ unsigned char ch;
+ unsigned char *name;
+ wchar_t wch;
+ } opr;
+} bracket_elem_t;
+
+
+/* Inline functions for bitset operation. */
+static inline void
+bitset_not (bitset set)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_UINTS; ++bitset_i)
+ set[bitset_i] = ~set[bitset_i];
+}
+
+static inline void
+bitset_merge (bitset dest, const bitset src)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_UINTS; ++bitset_i)
+ dest[bitset_i] |= src[bitset_i];
+}
+
+static inline void
+bitset_not_merge (bitset dest, const bitset src)
+{
+ int i;
+ for (i = 0; i < BITSET_UINTS; ++i)
+ dest[i] |= ~src[i];
+}
+
+static inline void
+bitset_mask (bitset dest, const bitset src)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_UINTS; ++bitset_i)
+ dest[bitset_i] &= src[bitset_i];
+}
+
+#if defined RE_ENABLE_I18N && !defined RE_NO_INTERNAL_PROTOTYPES
+/* Inline functions for re_string. */
+static inline int
+internal_function
+re_string_char_size_at (const re_string_t *pstr, int idx)
+{
+ int byte_idx;
+ if (pstr->mb_cur_max == 1)
+ return 1;
+ for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
+ if (pstr->wcs[idx + byte_idx] != WEOF)
+ break;
+ return byte_idx;
+}
+
+static inline wint_t
+internal_function
+re_string_wchar_at (const re_string_t *pstr, int idx)
+{
+ if (pstr->mb_cur_max == 1)
+ return (wint_t) pstr->mbs[idx];
+ return (wint_t) pstr->wcs[idx];
+}
+
+static int
+internal_function
+re_string_elem_size_at (const re_string_t *pstr, int idx)
+{
+#ifdef _LIBC
+ const unsigned char *p, *extra;
+ const int32_t *table, *indirect;
+ int32_t tmp;
+# include <locale/weight.h>
+ uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+
+ if (nrules != 0)
+ {
+ table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_INDIRECTMB);
+ p = pstr->mbs + idx;
+ tmp = findidx (&p);
+ return p - pstr->mbs - idx;
+ }
+ else
+#endif /* _LIBC */
+ return 1;
+}
+#endif /* RE_ENABLE_I18N */
+
+#endif /* _REGEX_INTERNAL_H */
diff --git a/gnu/lib/libregex/regexec.c b/gnu/lib/libregex/regexec.c
new file mode 100644
index 0000000..3c226e3
--- /dev/null
+++ b/gnu/lib/libregex/regexec.c
@@ -0,0 +1,4327 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
+ int n) internal_function;
+static void match_ctx_clean (re_match_context_t *mctx) internal_function;
+static void match_ctx_free (re_match_context_t *cache) internal_function;
+static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node,
+ int str_idx, int from, int to)
+ internal_function;
+static int search_cur_bkref_entry (re_match_context_t *mctx, int str_idx)
+ internal_function;
+static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node,
+ int str_idx) internal_function;
+static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop,
+ int node, int str_idx)
+ internal_function;
+static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
+ re_dfastate_t **limited_sts, int last_node,
+ int last_str_idx)
+ internal_function;
+static reg_errcode_t re_search_internal (const regex_t *preg,
+ const char *string, int length,
+ int start, int range, int stop,
+ size_t nmatch, regmatch_t pmatch[],
+ int eflags) internal_function;
+static int re_search_2_stub (struct re_pattern_buffer *bufp,
+ const char *string1, int length1,
+ const char *string2, int length2,
+ int start, int range, struct re_registers *regs,
+ int stop, int ret_len) internal_function;
+static int re_search_stub (struct re_pattern_buffer *bufp,
+ const char *string, int length, int start,
+ int range, int stop, struct re_registers *regs,
+ int ret_len) internal_function;
+static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch,
+ int nregs, int regs_allocated) internal_function;
+static inline re_dfastate_t *acquire_init_state_context
+ (reg_errcode_t *err, const re_match_context_t *mctx, int idx)
+ __attribute ((always_inline)) internal_function;
+static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx)
+ internal_function;
+static int check_matching (re_match_context_t *mctx, int fl_longest_match,
+ int *p_match_first)
+ internal_function;
+static int check_halt_node_context (const re_dfa_t *dfa, int node,
+ unsigned int context) internal_function;
+static int check_halt_state_context (const re_match_context_t *mctx,
+ const re_dfastate_t *state, int idx)
+ internal_function;
+static void update_regs (re_dfa_t *dfa, regmatch_t *pmatch,
+ regmatch_t *prev_idx_match, int cur_node,
+ int cur_idx, int nmatch) internal_function;
+static int proceed_next_node (const re_match_context_t *mctx,
+ int nregs, regmatch_t *regs,
+ int *pidx, int node, re_node_set *eps_via_nodes,
+ struct re_fail_stack_t *fs) internal_function;
+static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs,
+ int str_idx, int dest_node, int nregs,
+ regmatch_t *regs,
+ re_node_set *eps_via_nodes) internal_function;
+static int pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs,
+ regmatch_t *regs, re_node_set *eps_via_nodes) internal_function;
+static reg_errcode_t set_regs (const regex_t *preg,
+ const re_match_context_t *mctx,
+ size_t nmatch, regmatch_t *pmatch,
+ int fl_backtrack) internal_function;
+static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs) internal_function;
+
+#ifdef RE_ENABLE_I18N
+static int sift_states_iter_mb (const re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int node_idx, int str_idx, int max_str_idx) internal_function;
+#endif /* RE_ENABLE_I18N */
+static reg_errcode_t sift_states_backward (re_match_context_t *mctx,
+ re_sift_context_t *sctx) internal_function;
+static reg_errcode_t build_sifted_states (re_match_context_t *mctx,
+ re_sift_context_t *sctx, int str_idx,
+ re_node_set *cur_dest) internal_function;
+static reg_errcode_t update_cur_sifted_state (re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int str_idx,
+ re_node_set *dest_nodes) internal_function;
+static reg_errcode_t add_epsilon_src_nodes (re_dfa_t *dfa,
+ re_node_set *dest_nodes,
+ const re_node_set *candidates) internal_function;
+static reg_errcode_t sub_epsilon_src_nodes (re_dfa_t *dfa, int node,
+ re_node_set *dest_nodes,
+ const re_node_set *and_nodes) internal_function;
+static int check_dst_limits (re_match_context_t *mctx, re_node_set *limits,
+ int dst_node, int dst_idx, int src_node,
+ int src_idx) internal_function;
+static int check_dst_limits_calc_pos_1 (re_match_context_t *mctx,
+ int boundaries, int subexp_idx,
+ int from_node, int bkref_idx) internal_function;
+static int check_dst_limits_calc_pos (re_match_context_t *mctx,
+ int limit, int subexp_idx,
+ int node, int str_idx,
+ int bkref_idx) internal_function;
+static reg_errcode_t check_subexp_limits (re_dfa_t *dfa,
+ re_node_set *dest_nodes,
+ const re_node_set *candidates,
+ re_node_set *limits,
+ struct re_backref_cache_entry *bkref_ents,
+ int str_idx) internal_function;
+static reg_errcode_t sift_states_bkref (re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int str_idx, const re_node_set *candidates) internal_function;
+static reg_errcode_t clean_state_log_if_needed (re_match_context_t *mctx,
+ int next_state_log_idx) internal_function;
+static reg_errcode_t merge_state_array (re_dfa_t *dfa, re_dfastate_t **dst,
+ re_dfastate_t **src, int num) internal_function;
+static re_dfastate_t *find_recover_state (reg_errcode_t *err,
+ re_match_context_t *mctx) internal_function;
+static re_dfastate_t *transit_state (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *state) internal_function;
+static re_dfastate_t *merge_state_with_log (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *next_state) internal_function;
+static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx,
+ re_node_set *cur_nodes,
+ int str_idx) internal_function;
+#if 0
+static re_dfastate_t *transit_state_sb (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *pstate) internal_function;
+#endif
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t transit_state_mb (re_match_context_t *mctx,
+ re_dfastate_t *pstate) internal_function;
+#endif /* RE_ENABLE_I18N */
+static reg_errcode_t transit_state_bkref (re_match_context_t *mctx,
+ const re_node_set *nodes) internal_function;
+static reg_errcode_t get_subexp (re_match_context_t *mctx,
+ int bkref_node, int bkref_str_idx) internal_function;
+static reg_errcode_t get_subexp_sub (re_match_context_t *mctx,
+ const re_sub_match_top_t *sub_top,
+ re_sub_match_last_t *sub_last,
+ int bkref_node, int bkref_str) internal_function;
+static int find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
+ int subexp_idx, int type) internal_function;
+static reg_errcode_t check_arrival (re_match_context_t *mctx,
+ state_array_t *path, int top_node,
+ int top_str, int last_node, int last_str,
+ int type) internal_function;
+static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx,
+ int str_idx,
+ re_node_set *cur_nodes,
+ re_node_set *next_nodes) internal_function;
+static reg_errcode_t check_arrival_expand_ecl (re_dfa_t *dfa,
+ re_node_set *cur_nodes,
+ int ex_subexp, int type) internal_function;
+static reg_errcode_t check_arrival_expand_ecl_sub (re_dfa_t *dfa,
+ re_node_set *dst_nodes,
+ int target, int ex_subexp,
+ int type) internal_function;
+static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx,
+ re_node_set *cur_nodes, int cur_str,
+ int subexp_num, int type) internal_function;
+static int build_trtable (re_dfa_t *dfa,
+ re_dfastate_t *state) internal_function;
+#ifdef RE_ENABLE_I18N
+static int check_node_accept_bytes (re_dfa_t *dfa, int node_idx,
+ const re_string_t *input, int idx) internal_function;
+# ifdef _LIBC
+static unsigned int find_collation_sequence_value (const unsigned char *mbs,
+ size_t name_len) internal_function;
+# endif /* _LIBC */
+#endif /* RE_ENABLE_I18N */
+static int group_nodes_into_DFAstates (re_dfa_t *dfa,
+ const re_dfastate_t *state,
+ re_node_set *states_node,
+ bitset *states_ch) internal_function;
+static int check_node_accept (const re_match_context_t *mctx,
+ const re_token_t *node, int idx) internal_function;
+static reg_errcode_t extend_buffers (re_match_context_t *mctx) internal_function;
+
+/* Entry point for POSIX code. */
+
+/* regexec searches for a given pattern, specified by PREG, in the
+ string STRING.
+
+ If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+ `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
+ least NMATCH elements, and we set them to the offsets of the
+ corresponding matched substrings.
+
+ EFLAGS specifies `execution flags' which affect matching: if
+ REG_NOTBOL is set, then ^ does not match at the beginning of the
+ string; if REG_NOTEOL is set, then $ does not match at the end.
+
+ We return 0 if we find a match and REG_NOMATCH if not. */
+
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+ const regex_t *__restrict preg;
+ const char *__restrict string;
+ size_t nmatch;
+ regmatch_t pmatch[];
+ int eflags;
+{
+ reg_errcode_t err;
+ int start, length;
+
+ if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND))
+ return REG_BADPAT;
+
+ if (eflags & REG_STARTEND)
+ {
+ start = pmatch[0].rm_so;
+ length = pmatch[0].rm_eo;
+ }
+ else
+ {
+ start = 0;
+ length = strlen (string);
+ }
+ if (preg->no_sub)
+ err = re_search_internal (preg, string, length, start, length - start,
+ length, 0, NULL, eflags);
+ else
+ err = re_search_internal (preg, string, length, start, length - start,
+ length, nmatch, pmatch, eflags);
+ return err != REG_NOERROR;
+}
+
+#ifdef _LIBC
+# include <shlib-compat.h>
+versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
+
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
+__typeof__ (__regexec) __compat_regexec;
+
+int
+attribute_compat_text_section
+__compat_regexec (const regex_t *__restrict preg,
+ const char *__restrict string, size_t nmatch,
+ regmatch_t pmatch[], int eflags)
+{
+ return regexec (preg, string, nmatch, pmatch,
+ eflags & (REG_NOTBOL | REG_NOTEOL));
+}
+compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
+# endif
+#endif
+
+/* Entry points for GNU code. */
+
+/* re_match, re_search, re_match_2, re_search_2
+
+ The former two functions operate on STRING with length LENGTH,
+ while the later two operate on concatenation of STRING1 and STRING2
+ with lengths LENGTH1 and LENGTH2, respectively.
+
+ re_match() matches the compiled pattern in BUFP against the string,
+ starting at index START.
+
+ re_search() first tries matching at index START, then it tries to match
+ starting from index START + 1, and so on. The last start position tried
+ is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same
+ way as re_match().)
+
+ The parameter STOP of re_{match,search}_2 specifies that no match exceeding
+ the first STOP characters of the concatenation of the strings should be
+ concerned.
+
+ If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match
+ and all groups is stroed in REGS. (For the "_2" variants, the offsets are
+ computed relative to the concatenation, not relative to the individual
+ strings.)
+
+ On success, re_match* functions return the length of the match, re_search*
+ return the position of the start of the match. Return value -1 means no
+ match was found and -2 indicates an internal error. */
+
+int
+re_match (bufp, string, length, start, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int length, start;
+ struct re_registers *regs;
+{
+ return re_search_stub (bufp, string, length, start, 0, length, regs, 1);
+}
+#ifdef _LIBC
+weak_alias (__re_match, re_match)
+#endif
+
+int
+re_search (bufp, string, length, start, range, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int length, start, range;
+ struct re_registers *regs;
+{
+ return re_search_stub (bufp, string, length, start, range, length, regs, 0);
+}
+#ifdef _LIBC
+weak_alias (__re_search, re_search)
+#endif
+
+int
+re_match_2 (bufp, string1, length1, string2, length2, start, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int length1, length2, start, stop;
+ struct re_registers *regs;
+{
+ return re_search_2_stub (bufp, string1, length1, string2, length2,
+ start, 0, regs, stop, 1);
+}
+#ifdef _LIBC
+weak_alias (__re_match_2, re_match_2)
+#endif
+
+int
+re_search_2 (bufp, string1, length1, string2, length2, start, range, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int length1, length2, start, range, stop;
+ struct re_registers *regs;
+{
+ return re_search_2_stub (bufp, string1, length1, string2, length2,
+ start, range, regs, stop, 0);
+}
+#ifdef _LIBC
+weak_alias (__re_search_2, re_search_2)
+#endif
+
+static int
+re_search_2_stub (bufp, string1, length1, string2, length2, start, range, regs,
+ stop, ret_len)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int length1, length2, start, range, stop, ret_len;
+ struct re_registers *regs;
+{
+ const char *str;
+ int rval;
+ int len = length1 + length2;
+ int free_str = 0;
+
+ if (BE (length1 < 0 || length2 < 0 || stop < 0, 0))
+ return -2;
+
+ /* Concatenate the strings. */
+ if (length2 > 0)
+ if (length1 > 0)
+ {
+ char *s = re_malloc (char, len);
+
+ if (BE (s == NULL, 0))
+ return -2;
+ memcpy (s, string1, length1);
+ memcpy (s + length1, string2, length2);
+ str = s;
+ free_str = 1;
+ }
+ else
+ str = string2;
+ else
+ str = string1;
+
+ rval = re_search_stub (bufp, str, len, start, range, stop, regs,
+ ret_len);
+ if (free_str)
+ re_free ((char *) str);
+ return rval;
+}
+
+/* The parameters have the same meaning as those of re_search.
+ Additional parameters:
+ If RET_LEN is nonzero the length of the match is returned (re_match style);
+ otherwise the position of the match is returned. */
+
+static int
+re_search_stub (bufp, string, length, start, range, stop, regs, ret_len)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int length, start, range, stop, ret_len;
+ struct re_registers *regs;
+{
+ reg_errcode_t result;
+ regmatch_t *pmatch;
+ int nregs, rval;
+ int eflags = 0;
+
+ /* Check for out-of-range. */
+ if (BE (start < 0 || start > length, 0))
+ return -1;
+ if (BE (start + range > length, 0))
+ range = length - start;
+ else if (BE (start + range < 0, 0))
+ range = -start;
+
+ eflags |= (bufp->not_bol) ? REG_NOTBOL : 0;
+ eflags |= (bufp->not_eol) ? REG_NOTEOL : 0;
+
+ /* Compile fastmap if we haven't yet. */
+ if (range > 0 && bufp->fastmap != NULL && !bufp->fastmap_accurate)
+ re_compile_fastmap (bufp);
+
+ if (BE (bufp->no_sub, 0))
+ regs = NULL;
+
+ /* We need at least 1 register. */
+ if (regs == NULL)
+ nregs = 1;
+ else if (BE (bufp->regs_allocated == REGS_FIXED &&
+ regs->num_regs < bufp->re_nsub + 1, 0))
+ {
+ nregs = regs->num_regs;
+ if (BE (nregs < 1, 0))
+ {
+ /* Nothing can be copied to regs. */
+ regs = NULL;
+ nregs = 1;
+ }
+ }
+ else
+ nregs = bufp->re_nsub + 1;
+ pmatch = re_malloc (regmatch_t, nregs);
+ if (BE (pmatch == NULL, 0))
+ return -2;
+
+ result = re_search_internal (bufp, string, length, start, range, stop,
+ nregs, pmatch, eflags);
+
+ rval = 0;
+
+ /* I hope we needn't fill ther regs with -1's when no match was found. */
+ if (result != REG_NOERROR)
+ rval = -1;
+ else if (regs != NULL)
+ {
+ /* If caller wants register contents data back, copy them. */
+ bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs,
+ bufp->regs_allocated);
+ if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0))
+ rval = -2;
+ }
+
+ if (BE (rval == 0, 1))
+ {
+ if (ret_len)
+ {
+ assert (pmatch[0].rm_so == start);
+ rval = pmatch[0].rm_eo - start;
+ }
+ else
+ rval = pmatch[0].rm_so;
+ }
+ re_free (pmatch);
+ return rval;
+}
+
+static unsigned
+re_copy_regs (regs, pmatch, nregs, regs_allocated)
+ struct re_registers *regs;
+ regmatch_t *pmatch;
+ int nregs, regs_allocated;
+{
+ int rval = REGS_REALLOCATE;
+ int i;
+ int need_regs = nregs + 1;
+ /* We need one extra element beyond `num_regs' for the `-1' marker GNU code
+ uses. */
+
+ /* Have the register data arrays been allocated? */
+ if (regs_allocated == REGS_UNALLOCATED)
+ { /* No. So allocate them with malloc. */
+ regs->start = re_malloc (regoff_t, need_regs);
+ regs->end = re_malloc (regoff_t, need_regs);
+ if (BE (regs->start == NULL, 0) || BE (regs->end == NULL, 0))
+ return REGS_UNALLOCATED;
+ regs->num_regs = need_regs;
+ }
+ else if (regs_allocated == REGS_REALLOCATE)
+ { /* Yes. If we need more elements than were already
+ allocated, reallocate them. If we need fewer, just
+ leave it alone. */
+ if (BE (need_regs > regs->num_regs, 0))
+ {
+ regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs);
+ regoff_t *new_end = re_realloc (regs->end, regoff_t, need_regs);
+ if (BE (new_start == NULL, 0) || BE (new_end == NULL, 0))
+ return REGS_UNALLOCATED;
+ regs->start = new_start;
+ regs->end = new_end;
+ regs->num_regs = need_regs;
+ }
+ }
+ else
+ {
+ assert (regs_allocated == REGS_FIXED);
+ /* This function may not be called with REGS_FIXED and nregs too big. */
+ assert (regs->num_regs >= nregs);
+ rval = REGS_FIXED;
+ }
+
+ /* Copy the regs. */
+ for (i = 0; i < nregs; ++i)
+ {
+ regs->start[i] = pmatch[i].rm_so;
+ regs->end[i] = pmatch[i].rm_eo;
+ }
+ for ( ; i < regs->num_regs; ++i)
+ regs->start[i] = regs->end[i] = -1;
+
+ return rval;
+}
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
+ this memory for recording register information. STARTS and ENDS
+ must be allocated using the malloc library routine, and must each
+ be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+ struct re_pattern_buffer *bufp;
+ struct re_registers *regs;
+ unsigned num_regs;
+ regoff_t *starts, *ends;
+{
+ if (num_regs)
+ {
+ bufp->regs_allocated = REGS_REALLOCATE;
+ regs->num_regs = num_regs;
+ regs->start = starts;
+ regs->end = ends;
+ }
+ else
+ {
+ bufp->regs_allocated = REGS_UNALLOCATED;
+ regs->num_regs = 0;
+ regs->start = regs->end = (regoff_t *) 0;
+ }
+}
+#ifdef _LIBC
+weak_alias (__re_set_registers, re_set_registers)
+#endif
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+int
+# ifdef _LIBC
+weak_function
+# endif
+re_exec (s)
+ const char *s;
+{
+ return 0 == regexec (&re_comp_buf, s, 0, NULL, 0);
+}
+#endif /* _REGEX_RE_COMP */
+
+/* Internal entry point. */
+
+/* Searches for a compiled pattern PREG in the string STRING, whose
+ length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same
+ mingings with regexec. START, and RANGE have the same meanings
+ with re_search.
+ Return REG_NOERROR if we find a match, and REG_NOMATCH if not,
+ otherwise return the error code.
+ Note: We assume front end functions already check ranges.
+ (START + RANGE >= 0 && START + RANGE <= LENGTH) */
+
+static reg_errcode_t
+re_search_internal (preg, string, length, start, range, stop, nmatch, pmatch,
+ eflags)
+ const regex_t *preg;
+ const char *string;
+ int length, start, range, stop, eflags;
+ size_t nmatch;
+ regmatch_t pmatch[];
+{
+ reg_errcode_t err;
+ re_dfa_t *dfa = (re_dfa_t *)preg->buffer;
+ int left_lim, right_lim, incr;
+ int fl_longest_match, match_first, match_kind, match_last = -1;
+ int extra_nmatch;
+ int sb, ch;
+#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+ re_match_context_t mctx = { .dfa = dfa };
+#else
+ re_match_context_t mctx;
+#endif
+ char *fastmap = (preg->fastmap != NULL && preg->fastmap_accurate
+ && range && !preg->can_be_null) ? preg->fastmap : NULL;
+ unsigned RE_TRANSLATE_TYPE t = (unsigned RE_TRANSLATE_TYPE) preg->translate;
+
+#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))
+ memset (&mctx, '\0', sizeof (re_match_context_t));
+ mctx.dfa = dfa;
+#endif
+
+ extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0;
+ nmatch -= extra_nmatch;
+
+ /* Check if the DFA haven't been compiled. */
+ if (BE (preg->used == 0 || dfa->init_state == NULL
+ || dfa->init_state_word == NULL || dfa->init_state_nl == NULL
+ || dfa->init_state_begbuf == NULL, 0))
+ return REG_NOMATCH;
+
+#ifdef DEBUG
+ /* We assume front-end functions already check them. */
+ assert (start + range >= 0 && start + range <= length);
+#endif
+
+ /* If initial states with non-begbuf contexts have no elements,
+ the regex must be anchored. If preg->newline_anchor is set,
+ we'll never use init_state_nl, so do not check it. */
+ if (dfa->init_state->nodes.nelem == 0
+ && dfa->init_state_word->nodes.nelem == 0
+ && (dfa->init_state_nl->nodes.nelem == 0
+ || !preg->newline_anchor))
+ {
+ if (start != 0 && start + range != 0)
+ return REG_NOMATCH;
+ start = range = 0;
+ }
+
+ /* We must check the longest matching, if nmatch > 0. */
+ fl_longest_match = (nmatch != 0 || dfa->nbackref);
+
+ err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1,
+ preg->translate, preg->syntax & RE_ICASE, dfa);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ mctx.input.stop = stop;
+ mctx.input.raw_stop = stop;
+ mctx.input.newline_anchor = preg->newline_anchor;
+
+ err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* We will log all the DFA states through which the dfa pass,
+ if nmatch > 1, or this dfa has "multibyte node", which is a
+ back-reference or a node which can accept multibyte character or
+ multi character collating element. */
+ if (nmatch > 1 || dfa->has_mb_node)
+ {
+ mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1);
+ if (BE (mctx.state_log == NULL, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ }
+ else
+ mctx.state_log = NULL;
+
+ match_first = start;
+ mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
+ : CONTEXT_NEWLINE | CONTEXT_BEGBUF;
+
+ /* Check incrementally whether of not the input string match. */
+ incr = (range < 0) ? -1 : 1;
+ left_lim = (range < 0) ? start + range : start;
+ right_lim = (range < 0) ? start : start + range;
+ sb = dfa->mb_cur_max == 1;
+ match_kind =
+ (fastmap
+ ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0)
+ | (range >= 0 ? 2 : 0)
+ | (t != NULL ? 1 : 0))
+ : 8);
+
+ for (;; match_first += incr)
+ {
+ err = REG_NOMATCH;
+ if (match_first < left_lim || right_lim < match_first)
+ goto free_return;
+
+ /* Advance as rapidly as possible through the string, until we
+ find a plausible place to start matching. This may be done
+ with varying efficiency, so there are various possibilities:
+ only the most common of them are specialized, in order to
+ save on code size. We use a switch statement for speed. */
+ switch (match_kind)
+ {
+ case 8:
+ /* No fastmap. */
+ break;
+
+ case 7:
+ /* Fastmap with single-byte translation, match forward. */
+ while (BE (match_first < right_lim, 1)
+ && !fastmap[t[(unsigned char) string[match_first]]])
+ ++match_first;
+ goto forward_match_found_start_or_reached_end;
+
+ case 6:
+ /* Fastmap without translation, match forward. */
+ while (BE (match_first < right_lim, 1)
+ && !fastmap[(unsigned char) string[match_first]])
+ ++match_first;
+
+ forward_match_found_start_or_reached_end:
+ if (BE (match_first == right_lim, 0))
+ {
+ ch = match_first >= length
+ ? 0 : (unsigned char) string[match_first];
+ if (!fastmap[t ? t[ch] : ch])
+ goto free_return;
+ }
+ break;
+
+ case 4:
+ case 5:
+ /* Fastmap without multi-byte translation, match backwards. */
+ while (match_first >= left_lim)
+ {
+ ch = match_first >= length
+ ? 0 : (unsigned char) string[match_first];
+ if (fastmap[t ? t[ch] : ch])
+ break;
+ --match_first;
+ }
+ if (match_first < left_lim)
+ goto free_return;
+ break;
+
+ default:
+ /* In this case, we can't determine easily the current byte,
+ since it might be a component byte of a multibyte
+ character. Then we use the constructed buffer instead. */
+ for (;;)
+ {
+ /* If MATCH_FIRST is out of the valid range, reconstruct the
+ buffers. */
+ unsigned int offset = match_first - mctx.input.raw_mbs_idx;
+ if (BE (offset >= (unsigned int) mctx.input.valid_raw_len, 0))
+ {
+ err = re_string_reconstruct (&mctx.input, match_first,
+ eflags);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ offset = match_first - mctx.input.raw_mbs_idx;
+ }
+ /* If MATCH_FIRST is out of the buffer, leave it as '\0'.
+ Note that MATCH_FIRST must not be smaller than 0. */
+ ch = (match_first >= length
+ ? 0 : re_string_byte_at (&mctx.input, offset));
+ if (fastmap[ch])
+ break;
+ match_first += incr;
+ if (match_first < left_lim || match_first > right_lim)
+ {
+ err = REG_NOMATCH;
+ goto free_return;
+ }
+ }
+ break;
+ }
+
+ /* Reconstruct the buffers so that the matcher can assume that
+ the matching starts from the beginning of the buffer. */
+ err = re_string_reconstruct (&mctx.input, match_first, eflags);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+#ifdef RE_ENABLE_I18N
+ /* Don't consider this char as a possible match start if it part,
+ yet isn't the head, of a multibyte character. */
+ if (!sb && !re_string_first_byte (&mctx.input, 0))
+ continue;
+#endif
+
+ /* It seems to be appropriate one, then use the matcher. */
+ /* We assume that the matching starts from 0. */
+ mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0;
+ match_last = check_matching (&mctx, fl_longest_match,
+ range >= 0 ? &match_first : NULL);
+ if (match_last != -1)
+ {
+ if (BE (match_last == -2, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ else
+ {
+ mctx.match_last = match_last;
+ if ((!preg->no_sub && nmatch > 1) || dfa->nbackref)
+ {
+ re_dfastate_t *pstate = mctx.state_log[match_last];
+ mctx.last_node = check_halt_state_context (&mctx, pstate,
+ match_last);
+ }
+ if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match)
+ || dfa->nbackref)
+ {
+ err = prune_impossible_nodes (&mctx);
+ if (err == REG_NOERROR)
+ break;
+ if (BE (err != REG_NOMATCH, 0))
+ goto free_return;
+ match_last = -1;
+ }
+ else
+ break; /* We found a match. */
+ }
+ }
+
+ match_ctx_clean (&mctx);
+ }
+
+#ifdef DEBUG
+ assert (match_last != -1);
+ assert (err == REG_NOERROR);
+#endif
+
+ /* Set pmatch[] if we need. */
+ if (nmatch > 0)
+ {
+ int reg_idx;
+
+ /* Initialize registers. */
+ for (reg_idx = 1; reg_idx < nmatch; ++reg_idx)
+ pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1;
+
+ /* Set the points where matching start/end. */
+ pmatch[0].rm_so = 0;
+ pmatch[0].rm_eo = mctx.match_last;
+
+ if (!preg->no_sub && nmatch > 1)
+ {
+ err = set_regs (preg, &mctx, nmatch, pmatch,
+ dfa->has_plural_match && dfa->nbackref > 0);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+
+ /* At last, add the offset to the each registers, since we slided
+ the buffers so that we could assume that the matching starts
+ from 0. */
+ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
+ if (pmatch[reg_idx].rm_so != -1)
+ {
+#ifdef RE_ENABLE_I18N
+ if (BE (mctx.input.offsets_needed != 0, 0))
+ {
+ if (pmatch[reg_idx].rm_so == mctx.input.valid_len)
+ pmatch[reg_idx].rm_so += mctx.input.valid_raw_len - mctx.input.valid_len;
+ else
+ pmatch[reg_idx].rm_so = mctx.input.offsets[pmatch[reg_idx].rm_so];
+ if (pmatch[reg_idx].rm_eo == mctx.input.valid_len)
+ pmatch[reg_idx].rm_eo += mctx.input.valid_raw_len - mctx.input.valid_len;
+ else
+ pmatch[reg_idx].rm_eo = mctx.input.offsets[pmatch[reg_idx].rm_eo];
+ }
+#else
+ assert (mctx.input.offsets_needed == 0);
+#endif
+ pmatch[reg_idx].rm_so += match_first;
+ pmatch[reg_idx].rm_eo += match_first;
+ }
+ for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx)
+ {
+ pmatch[nmatch + reg_idx].rm_so = -1;
+ pmatch[nmatch + reg_idx].rm_eo = -1;
+ }
+
+ if (dfa->subexp_map)
+ for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++)
+ if (dfa->subexp_map[reg_idx] != reg_idx)
+ {
+ pmatch[reg_idx + 1].rm_so
+ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so;
+ pmatch[reg_idx + 1].rm_eo
+ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo;
+ }
+ }
+
+ free_return:
+ re_free (mctx.state_log);
+ if (dfa->nbackref)
+ match_ctx_free (&mctx);
+ re_string_destruct (&mctx.input);
+ return err;
+}
+
+static reg_errcode_t
+prune_impossible_nodes (mctx)
+ re_match_context_t *mctx;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ int halt_node, match_last;
+ reg_errcode_t ret;
+ re_dfastate_t **sifted_states;
+ re_dfastate_t **lim_states = NULL;
+ re_sift_context_t sctx;
+#ifdef DEBUG
+ assert (mctx->state_log != NULL);
+#endif
+ match_last = mctx->match_last;
+ halt_node = mctx->last_node;
+ sifted_states = re_malloc (re_dfastate_t *, match_last + 1);
+ if (BE (sifted_states == NULL, 0))
+ {
+ ret = REG_ESPACE;
+ goto free_return;
+ }
+ if (dfa->nbackref)
+ {
+ lim_states = re_malloc (re_dfastate_t *, match_last + 1);
+ if (BE (lim_states == NULL, 0))
+ {
+ ret = REG_ESPACE;
+ goto free_return;
+ }
+ while (1)
+ {
+ memset (lim_states, '\0',
+ sizeof (re_dfastate_t *) * (match_last + 1));
+ sift_ctx_init (&sctx, sifted_states, lim_states, halt_node,
+ match_last);
+ ret = sift_states_backward (mctx, &sctx);
+ re_node_set_free (&sctx.limits);
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ if (sifted_states[0] != NULL || lim_states[0] != NULL)
+ break;
+ do
+ {
+ --match_last;
+ if (match_last < 0)
+ {
+ ret = REG_NOMATCH;
+ goto free_return;
+ }
+ } while (mctx->state_log[match_last] == NULL
+ || !mctx->state_log[match_last]->halt);
+ halt_node = check_halt_state_context (mctx,
+ mctx->state_log[match_last],
+ match_last);
+ }
+ ret = merge_state_array (dfa, sifted_states, lim_states,
+ match_last + 1);
+ re_free (lim_states);
+ lim_states = NULL;
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ }
+ else
+ {
+ sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last);
+ ret = sift_states_backward (mctx, &sctx);
+ re_node_set_free (&sctx.limits);
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ }
+ re_free (mctx->state_log);
+ mctx->state_log = sifted_states;
+ sifted_states = NULL;
+ mctx->last_node = halt_node;
+ mctx->match_last = match_last;
+ ret = REG_NOERROR;
+ free_return:
+ re_free (sifted_states);
+ re_free (lim_states);
+ return ret;
+}
+
+/* Acquire an initial state and return it.
+ We must select appropriate initial state depending on the context,
+ since initial states may have constraints like "\<", "^", etc.. */
+
+static inline re_dfastate_t *
+acquire_init_state_context (err, mctx, idx)
+ reg_errcode_t *err;
+ const re_match_context_t *mctx;
+ int idx;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ if (dfa->init_state->has_constraint)
+ {
+ unsigned int context;
+ context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags);
+ if (IS_WORD_CONTEXT (context))
+ return dfa->init_state_word;
+ else if (IS_ORDINARY_CONTEXT (context))
+ return dfa->init_state;
+ else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context))
+ return dfa->init_state_begbuf;
+ else if (IS_NEWLINE_CONTEXT (context))
+ return dfa->init_state_nl;
+ else if (IS_BEGBUF_CONTEXT (context))
+ {
+ /* It is relatively rare case, then calculate on demand. */
+ return re_acquire_state_context (err, dfa,
+ dfa->init_state->entrance_nodes,
+ context);
+ }
+ else
+ /* Must not happen? */
+ return dfa->init_state;
+ }
+ else
+ return dfa->init_state;
+}
+
+/* Check whether the regular expression match input string INPUT or not,
+ and return the index where the matching end, return -1 if not match,
+ or return -2 in case of an error.
+ FL_LONGEST_MATCH means we want the POSIX longest matching.
+ If P_MATCH_FIRST is not NULL, and the match fails, it is set to the
+ next place where we may want to try matching.
+ Note that the matcher assume that the maching starts from the current
+ index of the buffer. */
+
+static int
+check_matching (mctx, fl_longest_match, p_match_first)
+ re_match_context_t *mctx;
+ int fl_longest_match;
+ int *p_match_first;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int match = 0;
+ int match_last = -1;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+ re_dfastate_t *cur_state;
+ int at_init_state = p_match_first != NULL;
+ int next_start_idx = cur_str_idx;
+
+ err = REG_NOERROR;
+ cur_state = acquire_init_state_context (&err, mctx, cur_str_idx);
+ /* An initial state must not be NULL (invalid). */
+ if (BE (cur_state == NULL, 0))
+ {
+ assert (err == REG_ESPACE);
+ return -2;
+ }
+
+ if (mctx->state_log != NULL)
+ {
+ mctx->state_log[cur_str_idx] = cur_state;
+
+ /* Check OP_OPEN_SUBEXP in the initial state in case that we use them
+ later. E.g. Processing back references. */
+ if (BE (dfa->nbackref, 0))
+ {
+ at_init_state = 0;
+ err = check_subexp_matching_top (mctx, &cur_state->nodes, 0);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (cur_state->has_backref)
+ {
+ err = transit_state_bkref (mctx, &cur_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ }
+
+ /* If the RE accepts NULL string. */
+ if (BE (cur_state->halt, 0))
+ {
+ if (!cur_state->has_constraint
+ || check_halt_state_context (mctx, cur_state, cur_str_idx))
+ {
+ if (!fl_longest_match)
+ return cur_str_idx;
+ else
+ {
+ match_last = cur_str_idx;
+ match = 1;
+ }
+ }
+ }
+
+ while (!re_string_eoi (&mctx->input))
+ {
+ re_dfastate_t *old_state = cur_state;
+ int next_char_idx = re_string_cur_idx (&mctx->input) + 1;
+
+ if (BE (next_char_idx >= mctx->input.bufs_len, 0)
+ || (BE (next_char_idx >= mctx->input.valid_len, 0)
+ && mctx->input.valid_len < mctx->input.len))
+ {
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ assert (err == REG_ESPACE);
+ return -2;
+ }
+ }
+
+ cur_state = transit_state (&err, mctx, cur_state);
+ if (mctx->state_log != NULL)
+ cur_state = merge_state_with_log (&err, mctx, cur_state);
+
+ if (cur_state == NULL)
+ {
+ /* Reached the invalid state or an error. Try to recover a valid
+ state using the state log, if available and if we have not
+ already found a valid (even if not the longest) match. */
+ if (BE (err != REG_NOERROR, 0))
+ return -2;
+
+ if (mctx->state_log == NULL
+ || (match && !fl_longest_match)
+ || (cur_state = find_recover_state (&err, mctx)) == NULL)
+ break;
+ }
+
+ if (BE (at_init_state, 0))
+ {
+ if (old_state == cur_state)
+ next_start_idx = next_char_idx;
+ else
+ at_init_state = 0;
+ }
+
+ if (cur_state->halt)
+ {
+ /* Reached a halt state.
+ Check the halt state can satisfy the current context. */
+ if (!cur_state->has_constraint
+ || check_halt_state_context (mctx, cur_state,
+ re_string_cur_idx (&mctx->input)))
+ {
+ /* We found an appropriate halt state. */
+ match_last = re_string_cur_idx (&mctx->input);
+ match = 1;
+
+ /* We found a match, do not modify match_first below. */
+ p_match_first = NULL;
+ if (!fl_longest_match)
+ break;
+ }
+ }
+ }
+
+ if (p_match_first)
+ *p_match_first += next_start_idx;
+
+ return match_last;
+}
+
+/* Check NODE match the current context. */
+
+static int check_halt_node_context (dfa, node, context)
+ const re_dfa_t *dfa;
+ int node;
+ unsigned int context;
+{
+ re_token_type_t type = dfa->nodes[node].type;
+ unsigned int constraint = dfa->nodes[node].constraint;
+ if (type != END_OF_RE)
+ return 0;
+ if (!constraint)
+ return 1;
+ if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context))
+ return 0;
+ return 1;
+}
+
+/* Check the halt state STATE match the current context.
+ Return 0 if not match, if the node, STATE has, is a halt node and
+ match the context, return the node. */
+
+static int
+check_halt_state_context (mctx, state, idx)
+ const re_match_context_t *mctx;
+ const re_dfastate_t *state;
+ int idx;
+{
+ int i;
+ unsigned int context;
+#ifdef DEBUG
+ assert (state->halt);
+#endif
+ context = re_string_context_at (&mctx->input, idx, mctx->eflags);
+ for (i = 0; i < state->nodes.nelem; ++i)
+ if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context))
+ return state->nodes.elems[i];
+ return 0;
+}
+
+/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA
+ corresponding to the DFA).
+ Return the destination node, and update EPS_VIA_NODES, return -1 in case
+ of errors. */
+
+static int
+proceed_next_node (mctx, nregs, regs, pidx, node, eps_via_nodes, fs)
+ const re_match_context_t *mctx;
+ regmatch_t *regs;
+ int nregs, *pidx, node;
+ re_node_set *eps_via_nodes;
+ struct re_fail_stack_t *fs;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ int i, err, dest_node;
+ dest_node = -1;
+ if (IS_EPSILON_NODE (dfa->nodes[node].type))
+ {
+ re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes;
+ re_node_set *edests = &dfa->edests[node];
+ int dest_node;
+ err = re_node_set_insert (eps_via_nodes, node);
+ if (BE (err < 0, 0))
+ return -2;
+ /* Pick up a valid destination, or return -1 if none is found. */
+ for (dest_node = -1, i = 0; i < edests->nelem; ++i)
+ {
+ int candidate = edests->elems[i];
+ if (!re_node_set_contains (cur_nodes, candidate))
+ continue;
+ if (dest_node == -1)
+ dest_node = candidate;
+
+ else
+ {
+ /* In order to avoid infinite loop like "(a*)*", return the second
+ epsilon-transition if the first was already considered. */
+ if (re_node_set_contains (eps_via_nodes, dest_node))
+ return candidate;
+
+ /* Otherwise, push the second epsilon-transition on the fail stack. */
+ else if (fs != NULL
+ && push_fail_stack (fs, *pidx, candidate, nregs, regs,
+ eps_via_nodes))
+ return -2;
+
+ /* We know we are going to exit. */
+ break;
+ }
+ }
+ return dest_node;
+ }
+ else
+ {
+ int naccepted = 0;
+ re_token_type_t type = dfa->nodes[node].type;
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->nodes[node].accept_mb)
+ naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx);
+ else
+#endif /* RE_ENABLE_I18N */
+ if (type == OP_BACK_REF)
+ {
+ int subexp_idx = dfa->nodes[node].opr.idx + 1;
+ naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so;
+ if (fs != NULL)
+ {
+ if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1)
+ return -1;
+ else if (naccepted)
+ {
+ char *buf = (char *) re_string_get_buffer (&mctx->input);
+ if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
+ naccepted) != 0)
+ return -1;
+ }
+ }
+
+ if (naccepted == 0)
+ {
+ err = re_node_set_insert (eps_via_nodes, node);
+ if (BE (err < 0, 0))
+ return -2;
+ dest_node = dfa->edests[node].elems[0];
+ if (re_node_set_contains (&mctx->state_log[*pidx]->nodes,
+ dest_node))
+ return dest_node;
+ }
+ }
+
+ if (naccepted != 0
+ || check_node_accept (mctx, dfa->nodes + node, *pidx))
+ {
+ dest_node = dfa->nexts[node];
+ *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted;
+ if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL
+ || !re_node_set_contains (&mctx->state_log[*pidx]->nodes,
+ dest_node)))
+ return -1;
+ re_node_set_empty (eps_via_nodes);
+ return dest_node;
+ }
+ }
+ return -1;
+}
+
+static reg_errcode_t
+push_fail_stack (fs, str_idx, dest_node, nregs, regs, eps_via_nodes)
+ struct re_fail_stack_t *fs;
+ int str_idx, dest_node, nregs;
+ regmatch_t *regs;
+ re_node_set *eps_via_nodes;
+{
+ reg_errcode_t err;
+ int num = fs->num++;
+ if (fs->num == fs->alloc)
+ {
+ struct re_fail_stack_ent_t *new_array;
+ new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t)
+ * fs->alloc * 2));
+ if (new_array == NULL)
+ return REG_ESPACE;
+ fs->alloc *= 2;
+ fs->stack = new_array;
+ }
+ fs->stack[num].idx = str_idx;
+ fs->stack[num].node = dest_node;
+ fs->stack[num].regs = re_malloc (regmatch_t, nregs);
+ if (fs->stack[num].regs == NULL)
+ return REG_ESPACE;
+ memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs);
+ err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes);
+ return err;
+}
+
+static int
+pop_fail_stack (fs, pidx, nregs, regs, eps_via_nodes)
+ struct re_fail_stack_t *fs;
+ int *pidx, nregs;
+ regmatch_t *regs;
+ re_node_set *eps_via_nodes;
+{
+ int num = --fs->num;
+ assert (num >= 0);
+ *pidx = fs->stack[num].idx;
+ memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs);
+ re_node_set_free (eps_via_nodes);
+ re_free (fs->stack[num].regs);
+ *eps_via_nodes = fs->stack[num].eps_via_nodes;
+ return fs->stack[num].node;
+}
+
+/* Set the positions where the subexpressions are starts/ends to registers
+ PMATCH.
+ Note: We assume that pmatch[0] is already set, and
+ pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */
+
+static reg_errcode_t
+set_regs (preg, mctx, nmatch, pmatch, fl_backtrack)
+ const regex_t *preg;
+ const re_match_context_t *mctx;
+ size_t nmatch;
+ regmatch_t *pmatch;
+ int fl_backtrack;
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ int idx, cur_node;
+ re_node_set eps_via_nodes;
+ struct re_fail_stack_t *fs;
+ struct re_fail_stack_t fs_body = { 0, 2, NULL };
+ regmatch_t *prev_idx_match;
+
+#ifdef DEBUG
+ assert (nmatch > 1);
+ assert (mctx->state_log != NULL);
+#endif
+ if (fl_backtrack)
+ {
+ fs = &fs_body;
+ fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc);
+ if (fs->stack == NULL)
+ return REG_ESPACE;
+ }
+ else
+ fs = NULL;
+
+ cur_node = dfa->init_node;
+ re_node_set_init_empty (&eps_via_nodes);
+
+ prev_idx_match = (regmatch_t *) alloca (sizeof (regmatch_t) * nmatch);
+ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
+
+ for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;)
+ {
+ update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
+
+ if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
+ {
+ int reg_idx;
+ if (fs)
+ {
+ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
+ if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1)
+ break;
+ if (reg_idx == nmatch)
+ {
+ re_node_set_free (&eps_via_nodes);
+ return free_fail_stack_return (fs);
+ }
+ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+ &eps_via_nodes);
+ }
+ else
+ {
+ re_node_set_free (&eps_via_nodes);
+ return REG_NOERROR;
+ }
+ }
+
+ /* Proceed to next node. */
+ cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node,
+ &eps_via_nodes, fs);
+
+ if (BE (cur_node < 0, 0))
+ {
+ if (BE (cur_node == -2, 0))
+ {
+ re_node_set_free (&eps_via_nodes);
+ free_fail_stack_return (fs);
+ return REG_ESPACE;
+ }
+ if (fs)
+ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+ &eps_via_nodes);
+ else
+ {
+ re_node_set_free (&eps_via_nodes);
+ return REG_NOMATCH;
+ }
+ }
+ }
+ re_node_set_free (&eps_via_nodes);
+ return free_fail_stack_return (fs);
+}
+
+static reg_errcode_t
+free_fail_stack_return (fs)
+ struct re_fail_stack_t *fs;
+{
+ if (fs)
+ {
+ int fs_idx;
+ for (fs_idx = 0; fs_idx < fs->num; ++fs_idx)
+ {
+ re_node_set_free (&fs->stack[fs_idx].eps_via_nodes);
+ re_free (fs->stack[fs_idx].regs);
+ }
+ re_free (fs->stack);
+ }
+ return REG_NOERROR;
+}
+
+static void
+update_regs (dfa, pmatch, prev_idx_match, cur_node, cur_idx, nmatch)
+ re_dfa_t *dfa;
+ regmatch_t *pmatch, *prev_idx_match;
+ int cur_node, cur_idx, nmatch;
+{
+ int type = dfa->nodes[cur_node].type;
+ if (type == OP_OPEN_SUBEXP)
+ {
+ int reg_num = dfa->nodes[cur_node].opr.idx + 1;
+
+ /* We are at the first node of this sub expression. */
+ if (reg_num < nmatch)
+ {
+ pmatch[reg_num].rm_so = cur_idx;
+ pmatch[reg_num].rm_eo = -1;
+ }
+ }
+ else if (type == OP_CLOSE_SUBEXP)
+ {
+ int reg_num = dfa->nodes[cur_node].opr.idx + 1;
+ if (reg_num < nmatch)
+ {
+ /* We are at the last node of this sub expression. */
+ if (pmatch[reg_num].rm_so < cur_idx)
+ {
+ pmatch[reg_num].rm_eo = cur_idx;
+ /* This is a non-empty match or we are not inside an optional
+ subexpression. Accept this right away. */
+ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
+ }
+ else
+ {
+ if (dfa->nodes[cur_node].opt_subexp
+ && prev_idx_match[reg_num].rm_so != -1)
+ /* We transited through an empty match for an optional
+ subexpression, like (a?)*, and this is not the subexp's
+ first match. Copy back the old content of the registers
+ so that matches of an inner subexpression are undone as
+ well, like in ((a?))*. */
+ memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch);
+ else
+ /* We completed a subexpression, but it may be part of
+ an optional one, so do not update PREV_IDX_MATCH. */
+ pmatch[reg_num].rm_eo = cur_idx;
+ }
+ }
+ }
+}
+
+/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0
+ and sift the nodes in each states according to the following rules.
+ Updated state_log will be wrote to STATE_LOG.
+
+ Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if...
+ 1. When STR_IDX == MATCH_LAST(the last index in the state_log):
+ If `a' isn't the LAST_NODE and `a' can't epsilon transit to
+ the LAST_NODE, we throw away the node `a'.
+ 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts
+ string `s' and transit to `b':
+ i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw
+ away the node `a'.
+ ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is
+ thrown away, we throw away the node `a'.
+ 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b':
+ i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the
+ node `a'.
+ ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away,
+ we throw away the node `a'. */
+
+#define STATE_NODE_CONTAINS(state,node) \
+ ((state) != NULL && re_node_set_contains (&(state)->nodes, node))
+
+static reg_errcode_t
+sift_states_backward (mctx, sctx)
+ re_match_context_t *mctx;
+ re_sift_context_t *sctx;
+{
+ reg_errcode_t err;
+ int null_cnt = 0;
+ int str_idx = sctx->last_str_idx;
+ re_node_set cur_dest;
+
+#ifdef DEBUG
+ assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL);
+#endif
+
+ /* Build sifted state_log[str_idx]. It has the nodes which can epsilon
+ transit to the last_node and the last_node itself. */
+ err = re_node_set_init_1 (&cur_dest, sctx->last_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* Then check each states in the state_log. */
+ while (str_idx > 0)
+ {
+ /* Update counters. */
+ null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0;
+ if (null_cnt > mctx->max_mb_elem_len)
+ {
+ memset (sctx->sifted_states, '\0',
+ sizeof (re_dfastate_t *) * str_idx);
+ re_node_set_free (&cur_dest);
+ return REG_NOERROR;
+ }
+ re_node_set_empty (&cur_dest);
+ --str_idx;
+
+ if (mctx->state_log[str_idx])
+ {
+ err = build_sifted_states (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+
+ /* Add all the nodes which satisfy the following conditions:
+ - It can epsilon transit to a node in CUR_DEST.
+ - It is in CUR_SRC.
+ And update state_log. */
+ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ err = REG_NOERROR;
+ free_return:
+ re_node_set_free (&cur_dest);
+ return err;
+}
+
+static reg_errcode_t
+build_sifted_states (mctx, sctx, str_idx, cur_dest)
+ re_match_context_t *mctx;
+ re_sift_context_t *sctx;
+ int str_idx;
+ re_node_set *cur_dest;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes;
+ int i;
+
+ /* Then build the next sifted state.
+ We build the next sifted state on `cur_dest', and update
+ `sifted_states[str_idx]' with `cur_dest'.
+ Note:
+ `cur_dest' is the sifted state from `state_log[str_idx + 1]'.
+ `cur_src' points the node_set of the old `state_log[str_idx]'
+ (with the epsilon nodes pre-filtered out). */
+ for (i = 0; i < cur_src->nelem; i++)
+ {
+ int prev_node = cur_src->elems[i];
+ int naccepted = 0;
+ int ret;
+
+#ifdef DEBUG
+ re_token_type_t type = dfa->nodes[prev_node].type;
+ assert (!IS_EPSILON_NODE (type));
+#endif
+#ifdef RE_ENABLE_I18N
+ /* If the node may accept `multi byte'. */
+ if (dfa->nodes[prev_node].accept_mb)
+ naccepted = sift_states_iter_mb (mctx, sctx, prev_node,
+ str_idx, sctx->last_str_idx);
+#endif /* RE_ENABLE_I18N */
+
+ /* We don't check backreferences here.
+ See update_cur_sifted_state(). */
+ if (!naccepted
+ && check_node_accept (mctx, dfa->nodes + prev_node, str_idx)
+ && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1],
+ dfa->nexts[prev_node]))
+ naccepted = 1;
+
+ if (naccepted == 0)
+ continue;
+
+ if (sctx->limits.nelem)
+ {
+ int to_idx = str_idx + naccepted;
+ if (check_dst_limits (mctx, &sctx->limits,
+ dfa->nexts[prev_node], to_idx,
+ prev_node, str_idx))
+ continue;
+ }
+ ret = re_node_set_insert (cur_dest, prev_node);
+ if (BE (ret == -1, 0))
+ return REG_ESPACE;
+ }
+
+ return REG_NOERROR;
+}
+
+/* Helper functions. */
+
+static reg_errcode_t
+clean_state_log_if_needed (mctx, next_state_log_idx)
+ re_match_context_t *mctx;
+ int next_state_log_idx;
+{
+ int top = mctx->state_log_top;
+
+ if (next_state_log_idx >= mctx->input.bufs_len
+ || (next_state_log_idx >= mctx->input.valid_len
+ && mctx->input.valid_len < mctx->input.len))
+ {
+ reg_errcode_t err;
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (top < next_state_log_idx)
+ {
+ memset (mctx->state_log + top + 1, '\0',
+ sizeof (re_dfastate_t *) * (next_state_log_idx - top));
+ mctx->state_log_top = next_state_log_idx;
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+merge_state_array (dfa, dst, src, num)
+ re_dfa_t *dfa;
+ re_dfastate_t **dst;
+ re_dfastate_t **src;
+ int num;
+{
+ int st_idx;
+ reg_errcode_t err;
+ for (st_idx = 0; st_idx < num; ++st_idx)
+ {
+ if (dst[st_idx] == NULL)
+ dst[st_idx] = src[st_idx];
+ else if (src[st_idx] != NULL)
+ {
+ re_node_set merged_set;
+ err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes,
+ &src[st_idx]->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ dst[st_idx] = re_acquire_state (&err, dfa, &merged_set);
+ re_node_set_free (&merged_set);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+update_cur_sifted_state (mctx, sctx, str_idx, dest_nodes)
+ re_match_context_t *mctx;
+ re_sift_context_t *sctx;
+ int str_idx;
+ re_node_set *dest_nodes;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ const re_node_set *candidates;
+ candidates = ((mctx->state_log[str_idx] == NULL) ? NULL
+ : &mctx->state_log[str_idx]->nodes);
+
+ if (dest_nodes->nelem == 0)
+ sctx->sifted_states[str_idx] = NULL;
+ else
+ {
+ if (candidates)
+ {
+ /* At first, add the nodes which can epsilon transit to a node in
+ DEST_NODE. */
+ err = add_epsilon_src_nodes (dfa, dest_nodes, candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* Then, check the limitations in the current sift_context. */
+ if (sctx->limits.nelem)
+ {
+ err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits,
+ mctx->bkref_ents, str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+
+ sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (candidates && mctx->state_log[str_idx]->has_backref)
+ {
+ err = sift_states_bkref (mctx, sctx, str_idx, candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+add_epsilon_src_nodes (dfa, dest_nodes, candidates)
+ re_dfa_t *dfa;
+ re_node_set *dest_nodes;
+ const re_node_set *candidates;
+{
+ reg_errcode_t err = REG_NOERROR;
+ int i;
+
+ re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (!state->inveclosure.alloc)
+ {
+ err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return REG_ESPACE;
+ for (i = 0; i < dest_nodes->nelem; i++)
+ re_node_set_merge (&state->inveclosure,
+ dfa->inveclosures + dest_nodes->elems[i]);
+ }
+ return re_node_set_add_intersect (dest_nodes, candidates,
+ &state->inveclosure);
+}
+
+static reg_errcode_t
+sub_epsilon_src_nodes (dfa, node, dest_nodes, candidates)
+ re_dfa_t *dfa;
+ int node;
+ re_node_set *dest_nodes;
+ const re_node_set *candidates;
+{
+ int ecl_idx;
+ reg_errcode_t err;
+ re_node_set *inv_eclosure = dfa->inveclosures + node;
+ re_node_set except_nodes;
+ re_node_set_init_empty (&except_nodes);
+ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
+ {
+ int cur_node = inv_eclosure->elems[ecl_idx];
+ if (cur_node == node)
+ continue;
+ if (IS_EPSILON_NODE (dfa->nodes[cur_node].type))
+ {
+ int edst1 = dfa->edests[cur_node].elems[0];
+ int edst2 = ((dfa->edests[cur_node].nelem > 1)
+ ? dfa->edests[cur_node].elems[1] : -1);
+ if ((!re_node_set_contains (inv_eclosure, edst1)
+ && re_node_set_contains (dest_nodes, edst1))
+ || (edst2 > 0
+ && !re_node_set_contains (inv_eclosure, edst2)
+ && re_node_set_contains (dest_nodes, edst2)))
+ {
+ err = re_node_set_add_intersect (&except_nodes, candidates,
+ dfa->inveclosures + cur_node);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&except_nodes);
+ return err;
+ }
+ }
+ }
+ }
+ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
+ {
+ int cur_node = inv_eclosure->elems[ecl_idx];
+ if (!re_node_set_contains (&except_nodes, cur_node))
+ {
+ int idx = re_node_set_contains (dest_nodes, cur_node) - 1;
+ re_node_set_remove_at (dest_nodes, idx);
+ }
+ }
+ re_node_set_free (&except_nodes);
+ return REG_NOERROR;
+}
+
+static int
+check_dst_limits (mctx, limits, dst_node, dst_idx, src_node, src_idx)
+ re_match_context_t *mctx;
+ re_node_set *limits;
+ int dst_node, dst_idx, src_node, src_idx;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ int lim_idx, src_pos, dst_pos;
+
+ int dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx);
+ int src_bkref_idx = search_cur_bkref_entry (mctx, src_idx);
+ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
+ {
+ int subexp_idx;
+ struct re_backref_cache_entry *ent;
+ ent = mctx->bkref_ents + limits->elems[lim_idx];
+ subexp_idx = dfa->nodes[ent->node].opr.idx;
+
+ dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
+ subexp_idx, dst_node, dst_idx,
+ dst_bkref_idx);
+ src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
+ subexp_idx, src_node, src_idx,
+ src_bkref_idx);
+
+ /* In case of:
+ <src> <dst> ( <subexp> )
+ ( <subexp> ) <src> <dst>
+ ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */
+ if (src_pos == dst_pos)
+ continue; /* This is unrelated limitation. */
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int
+check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, from_node, bkref_idx)
+ re_match_context_t *mctx;
+ int boundaries, subexp_idx, from_node, bkref_idx;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ re_node_set *eclosures = dfa->eclosures + from_node;
+ int node_idx;
+
+ /* Else, we are on the boundary: examine the nodes on the epsilon
+ closure. */
+ for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx)
+ {
+ int node = eclosures->elems[node_idx];
+ switch (dfa->nodes[node].type)
+ {
+ case OP_BACK_REF:
+ if (bkref_idx != -1)
+ {
+ struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx;
+ do
+ {
+ int dst, cpos;
+
+ if (ent->node != node)
+ continue;
+
+ if (subexp_idx <= 8 * sizeof (ent->eps_reachable_subexps_map)
+ && !(ent->eps_reachable_subexps_map & (1 << subexp_idx)))
+ continue;
+
+ /* Recurse trying to reach the OP_OPEN_SUBEXP and
+ OP_CLOSE_SUBEXP cases below. But, if the
+ destination node is the same node as the source
+ node, don't recurse because it would cause an
+ infinite loop: a regex that exhibits this behavior
+ is ()\1*\1* */
+ dst = dfa->edests[node].elems[0];
+ if (dst == from_node)
+ {
+ if (boundaries & 1)
+ return -1;
+ else /* if (boundaries & 2) */
+ return 0;
+ }
+
+ cpos =
+ check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
+ dst, bkref_idx);
+ if (cpos == -1 /* && (boundaries & 1) */)
+ return -1;
+ if (cpos == 0 && (boundaries & 2))
+ return 0;
+
+ ent->eps_reachable_subexps_map &= ~(1 << subexp_idx);
+ }
+ while (ent++->more);
+ }
+ break;
+
+ case OP_OPEN_SUBEXP:
+ if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx)
+ return -1;
+ break;
+
+ case OP_CLOSE_SUBEXP:
+ if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx)
+ return 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return (boundaries & 2) ? 1 : 0;
+}
+
+static int
+check_dst_limits_calc_pos (mctx, limit, subexp_idx, from_node, str_idx, bkref_idx)
+ re_match_context_t *mctx;
+ int limit, subexp_idx, from_node, str_idx, bkref_idx;
+{
+ struct re_backref_cache_entry *lim = mctx->bkref_ents + limit;
+ int boundaries;
+
+ /* If we are outside the range of the subexpression, return -1 or 1. */
+ if (str_idx < lim->subexp_from)
+ return -1;
+
+ if (lim->subexp_to < str_idx)
+ return 1;
+
+ /* If we are within the subexpression, return 0. */
+ boundaries = (str_idx == lim->subexp_from);
+ boundaries |= (str_idx == lim->subexp_to) << 1;
+ if (boundaries == 0)
+ return 0;
+
+ /* Else, examine epsilon closure. */
+ return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
+ from_node, bkref_idx);
+}
+
+/* Check the limitations of sub expressions LIMITS, and remove the nodes
+ which are against limitations from DEST_NODES. */
+
+static reg_errcode_t
+check_subexp_limits (dfa, dest_nodes, candidates, limits, bkref_ents, str_idx)
+ re_dfa_t *dfa;
+ re_node_set *dest_nodes;
+ const re_node_set *candidates;
+ re_node_set *limits;
+ struct re_backref_cache_entry *bkref_ents;
+ int str_idx;
+{
+ reg_errcode_t err;
+ int node_idx, lim_idx;
+
+ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
+ {
+ int subexp_idx;
+ struct re_backref_cache_entry *ent;
+ ent = bkref_ents + limits->elems[lim_idx];
+
+ if (str_idx <= ent->subexp_from || ent->str_idx < str_idx)
+ continue; /* This is unrelated limitation. */
+
+ subexp_idx = dfa->nodes[ent->node].opr.idx;
+ if (ent->subexp_to == str_idx)
+ {
+ int ops_node = -1;
+ int cls_node = -1;
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ re_token_type_t type = dfa->nodes[node].type;
+ if (type == OP_OPEN_SUBEXP
+ && subexp_idx == dfa->nodes[node].opr.idx)
+ ops_node = node;
+ else if (type == OP_CLOSE_SUBEXP
+ && subexp_idx == dfa->nodes[node].opr.idx)
+ cls_node = node;
+ }
+
+ /* Check the limitation of the open subexpression. */
+ /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */
+ if (ops_node >= 0)
+ {
+ err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ /* Check the limitation of the close subexpression. */
+ if (cls_node >= 0)
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ if (!re_node_set_contains (dfa->inveclosures + node,
+ cls_node)
+ && !re_node_set_contains (dfa->eclosures + node,
+ cls_node))
+ {
+ /* It is against this limitation.
+ Remove it form the current sifted state. */
+ err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ --node_idx;
+ }
+ }
+ }
+ else /* (ent->subexp_to != str_idx) */
+ {
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ re_token_type_t type = dfa->nodes[node].type;
+ if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP)
+ {
+ if (subexp_idx != dfa->nodes[node].opr.idx)
+ continue;
+ /* It is against this limitation.
+ Remove it form the current sifted state. */
+ err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+sift_states_bkref (mctx, sctx, str_idx, candidates)
+ re_match_context_t *mctx;
+ re_sift_context_t *sctx;
+ int str_idx;
+ const re_node_set *candidates;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int node_idx, node;
+ re_sift_context_t local_sctx;
+ int first_idx = search_cur_bkref_entry (mctx, str_idx);
+
+ if (first_idx == -1)
+ return REG_NOERROR;
+
+ local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */
+
+ for (node_idx = 0; node_idx < candidates->nelem; ++node_idx)
+ {
+ int enabled_idx;
+ re_token_type_t type;
+ struct re_backref_cache_entry *entry;
+ node = candidates->elems[node_idx];
+ type = dfa->nodes[node].type;
+ /* Avoid infinite loop for the REs like "()\1+". */
+ if (node == sctx->last_node && str_idx == sctx->last_str_idx)
+ continue;
+ if (type != OP_BACK_REF)
+ continue;
+
+ entry = mctx->bkref_ents + first_idx;
+ enabled_idx = first_idx;
+ do
+ {
+ int subexp_len, to_idx, dst_node;
+ re_dfastate_t *cur_state;
+
+ if (entry->node != node)
+ continue;
+ subexp_len = entry->subexp_to - entry->subexp_from;
+ to_idx = str_idx + subexp_len;
+ dst_node = (subexp_len ? dfa->nexts[node]
+ : dfa->edests[node].elems[0]);
+
+ if (to_idx > sctx->last_str_idx
+ || sctx->sifted_states[to_idx] == NULL
+ || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node)
+ || check_dst_limits (mctx, &sctx->limits, node,
+ str_idx, dst_node, to_idx))
+ continue;
+
+ if (local_sctx.sifted_states == NULL)
+ {
+ local_sctx = *sctx;
+ err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ local_sctx.last_node = node;
+ local_sctx.last_str_idx = str_idx;
+ err = re_node_set_insert (&local_sctx.limits, enabled_idx);
+ if (BE (err < 0, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ cur_state = local_sctx.sifted_states[str_idx];
+ err = sift_states_backward (mctx, &local_sctx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ if (sctx->limited_states != NULL)
+ {
+ err = merge_state_array (dfa, sctx->limited_states,
+ local_sctx.sifted_states,
+ str_idx + 1);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ local_sctx.sifted_states[str_idx] = cur_state;
+ re_node_set_remove (&local_sctx.limits, enabled_idx);
+
+ /* mctx->bkref_ents may have changed, reload the pointer. */
+ entry = mctx->bkref_ents + enabled_idx;
+ }
+ while (enabled_idx++, entry++->more);
+ }
+ err = REG_NOERROR;
+ free_return:
+ if (local_sctx.sifted_states != NULL)
+ {
+ re_node_set_free (&local_sctx.limits);
+ }
+
+ return err;
+}
+
+
+#ifdef RE_ENABLE_I18N
+static int
+sift_states_iter_mb (mctx, sctx, node_idx, str_idx, max_str_idx)
+ const re_match_context_t *mctx;
+ re_sift_context_t *sctx;
+ int node_idx, str_idx, max_str_idx;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ int naccepted;
+ /* Check the node can accept `multi byte'. */
+ naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx);
+ if (naccepted > 0 && str_idx + naccepted <= max_str_idx &&
+ !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted],
+ dfa->nexts[node_idx]))
+ /* The node can't accept the `multi byte', or the
+ destination was already thrown away, then the node
+ could't accept the current input `multi byte'. */
+ naccepted = 0;
+ /* Otherwise, it is sure that the node could accept
+ `naccepted' bytes input. */
+ return naccepted;
+}
+#endif /* RE_ENABLE_I18N */
+
+
+/* Functions for state transition. */
+
+/* Return the next state to which the current state STATE will transit by
+ accepting the current input byte, and update STATE_LOG if necessary.
+ If STATE can accept a multibyte char/collating element/back reference
+ update the destination of STATE_LOG. */
+
+static re_dfastate_t *
+transit_state (err, mctx, state)
+ reg_errcode_t *err;
+ re_match_context_t *mctx;
+ re_dfastate_t *state;
+{
+ re_dfastate_t **trtable;
+ unsigned char ch;
+
+#ifdef RE_ENABLE_I18N
+ /* If the current state can accept multibyte. */
+ if (BE (state->accept_mb, 0))
+ {
+ *err = transit_state_mb (mctx, state);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+#endif /* RE_ENABLE_I18N */
+
+ /* Then decide the next state with the single byte. */
+#if 0
+ if (0)
+ /* don't use transition table */
+ return transit_state_sb (err, mctx, state);
+#endif
+
+ /* Use transition table */
+ ch = re_string_fetch_byte (&mctx->input);
+ for (;;)
+ {
+ trtable = state->trtable;
+ if (BE (trtable != NULL, 1))
+ return trtable[ch];
+
+ trtable = state->word_trtable;
+ if (BE (trtable != NULL, 1))
+ {
+ unsigned int context;
+ context
+ = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input) - 1,
+ mctx->eflags);
+ if (IS_WORD_CONTEXT (context))
+ return trtable[ch + SBC_MAX];
+ else
+ return trtable[ch];
+ }
+
+ if (!build_trtable (mctx->dfa, state))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ /* Retry, we now have a transition table. */
+ }
+}
+
+/* Update the state_log if we need */
+re_dfastate_t *
+merge_state_with_log (err, mctx, next_state)
+ reg_errcode_t *err;
+ re_match_context_t *mctx;
+ re_dfastate_t *next_state;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ int cur_idx = re_string_cur_idx (&mctx->input);
+
+ if (cur_idx > mctx->state_log_top)
+ {
+ mctx->state_log[cur_idx] = next_state;
+ mctx->state_log_top = cur_idx;
+ }
+ else if (mctx->state_log[cur_idx] == 0)
+ {
+ mctx->state_log[cur_idx] = next_state;
+ }
+ else
+ {
+ re_dfastate_t *pstate;
+ unsigned int context;
+ re_node_set next_nodes, *log_nodes, *table_nodes = NULL;
+ /* If (state_log[cur_idx] != 0), it implies that cur_idx is
+ the destination of a multibyte char/collating element/
+ back reference. Then the next state is the union set of
+ these destinations and the results of the transition table. */
+ pstate = mctx->state_log[cur_idx];
+ log_nodes = pstate->entrance_nodes;
+ if (next_state != NULL)
+ {
+ table_nodes = next_state->entrance_nodes;
+ *err = re_node_set_init_union (&next_nodes, table_nodes,
+ log_nodes);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+ else
+ next_nodes = *log_nodes;
+ /* Note: We already add the nodes of the initial state,
+ then we don't need to add them here. */
+
+ context = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input) - 1,
+ mctx->eflags);
+ next_state = mctx->state_log[cur_idx]
+ = re_acquire_state_context (err, dfa, &next_nodes, context);
+ /* We don't need to check errors here, since the return value of
+ this function is next_state and ERR is already set. */
+
+ if (table_nodes != NULL)
+ re_node_set_free (&next_nodes);
+ }
+
+ if (BE (dfa->nbackref, 0) && next_state != NULL)
+ {
+ /* Check OP_OPEN_SUBEXP in the current state in case that we use them
+ later. We must check them here, since the back references in the
+ next state might use them. */
+ *err = check_subexp_matching_top (mctx, &next_state->nodes,
+ cur_idx);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+
+ /* If the next state has back references. */
+ if (next_state->has_backref)
+ {
+ *err = transit_state_bkref (mctx, &next_state->nodes);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ next_state = mctx->state_log[cur_idx];
+ }
+ }
+
+ return next_state;
+}
+
+/* Skip bytes in the input that correspond to part of a
+ multi-byte match, then look in the log for a state
+ from which to restart matching. */
+re_dfastate_t *
+find_recover_state (err, mctx)
+ reg_errcode_t *err;
+ re_match_context_t *mctx;
+{
+ re_dfastate_t *cur_state = NULL;
+ do
+ {
+ int max = mctx->state_log_top;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+
+ do
+ {
+ if (++cur_str_idx > max)
+ return NULL;
+ re_string_skip_bytes (&mctx->input, 1);
+ }
+ while (mctx->state_log[cur_str_idx] == NULL);
+
+ cur_state = merge_state_with_log (err, mctx, NULL);
+ }
+ while (err == REG_NOERROR && cur_state == NULL);
+ return cur_state;
+}
+
+/* Helper functions for transit_state. */
+
+/* From the node set CUR_NODES, pick up the nodes whose types are
+ OP_OPEN_SUBEXP and which have corresponding back references in the regular
+ expression. And register them to use them later for evaluating the
+ correspoding back references. */
+
+static reg_errcode_t
+check_subexp_matching_top (mctx, cur_nodes, str_idx)
+ re_match_context_t *mctx;
+ re_node_set *cur_nodes;
+ int str_idx;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ int node_idx;
+ reg_errcode_t err;
+
+ /* TODO: This isn't efficient.
+ Because there might be more than one nodes whose types are
+ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
+ nodes.
+ E.g. RE: (a){2} */
+ for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx)
+ {
+ int node = cur_nodes->elems[node_idx];
+ if (dfa->nodes[node].type == OP_OPEN_SUBEXP
+ && dfa->nodes[node].opr.idx < (8 * sizeof (dfa->used_bkref_map))
+ && dfa->used_bkref_map & (1 << dfa->nodes[node].opr.idx))
+ {
+ err = match_ctx_add_subtop (mctx, node, str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ return REG_NOERROR;
+}
+
+#if 0
+/* Return the next state to which the current state STATE will transit by
+ accepting the current input byte. */
+
+static re_dfastate_t *
+transit_state_sb (err, mctx, state)
+ reg_errcode_t *err;
+ re_match_context_t *mctx;
+ re_dfastate_t *state;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ re_node_set next_nodes;
+ re_dfastate_t *next_state;
+ int node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input);
+ unsigned int context;
+
+ *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt)
+ {
+ int cur_node = state->nodes.elems[node_cnt];
+ if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx))
+ {
+ *err = re_node_set_merge (&next_nodes,
+ dfa->eclosures + dfa->nexts[cur_node]);
+ if (BE (*err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return NULL;
+ }
+ }
+ }
+ context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags);
+ next_state = re_acquire_state_context (err, dfa, &next_nodes, context);
+ /* We don't need to check errors here, since the return value of
+ this function is next_state and ERR is already set. */
+
+ re_node_set_free (&next_nodes);
+ re_string_skip_bytes (&mctx->input, 1);
+ return next_state;
+}
+#endif
+
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t
+transit_state_mb (mctx, pstate)
+ re_match_context_t *mctx;
+ re_dfastate_t *pstate;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int i;
+
+ for (i = 0; i < pstate->nodes.nelem; ++i)
+ {
+ re_node_set dest_nodes, *new_nodes;
+ int cur_node_idx = pstate->nodes.elems[i];
+ int naccepted, dest_idx;
+ unsigned int context;
+ re_dfastate_t *dest_state;
+
+ if (!dfa->nodes[cur_node_idx].accept_mb)
+ continue;
+
+ if (dfa->nodes[cur_node_idx].constraint)
+ {
+ context = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input),
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint,
+ context))
+ continue;
+ }
+
+ /* How many bytes the node can accept? */
+ naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input,
+ re_string_cur_idx (&mctx->input));
+ if (naccepted == 0)
+ continue;
+
+ /* The node can accepts `naccepted' bytes. */
+ dest_idx = re_string_cur_idx (&mctx->input) + naccepted;
+ mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted
+ : mctx->max_mb_elem_len);
+ err = clean_state_log_if_needed (mctx, dest_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+#ifdef DEBUG
+ assert (dfa->nexts[cur_node_idx] != -1);
+#endif
+ new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx];
+
+ dest_state = mctx->state_log[dest_idx];
+ if (dest_state == NULL)
+ dest_nodes = *new_nodes;
+ else
+ {
+ err = re_node_set_init_union (&dest_nodes,
+ dest_state->entrance_nodes, new_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ context = re_string_context_at (&mctx->input, dest_idx - 1, mctx->eflags);
+ mctx->state_log[dest_idx]
+ = re_acquire_state_context (&err, dfa, &dest_nodes, context);
+ if (dest_state != NULL)
+ re_node_set_free (&dest_nodes);
+ if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0))
+ return err;
+ }
+ return REG_NOERROR;
+}
+#endif /* RE_ENABLE_I18N */
+
+static reg_errcode_t
+transit_state_bkref (mctx, nodes)
+ re_match_context_t *mctx;
+ const re_node_set *nodes;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int i;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+
+ for (i = 0; i < nodes->nelem; ++i)
+ {
+ int dest_str_idx, prev_nelem, bkc_idx;
+ int node_idx = nodes->elems[i];
+ unsigned int context;
+ const re_token_t *node = dfa->nodes + node_idx;
+ re_node_set *new_dest_nodes;
+
+ /* Check whether `node' is a backreference or not. */
+ if (node->type != OP_BACK_REF)
+ continue;
+
+ if (node->constraint)
+ {
+ context = re_string_context_at (&mctx->input, cur_str_idx,
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
+ continue;
+ }
+
+ /* `node' is a backreference.
+ Check the substring which the substring matched. */
+ bkc_idx = mctx->nbkref_ents;
+ err = get_subexp (mctx, node_idx, cur_str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* And add the epsilon closures (which is `new_dest_nodes') of
+ the backreference to appropriate state_log. */
+#ifdef DEBUG
+ assert (dfa->nexts[node_idx] != -1);
+#endif
+ for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx)
+ {
+ int subexp_len;
+ re_dfastate_t *dest_state;
+ struct re_backref_cache_entry *bkref_ent;
+ bkref_ent = mctx->bkref_ents + bkc_idx;
+ if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx)
+ continue;
+ subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from;
+ new_dest_nodes = (subexp_len == 0
+ ? dfa->eclosures + dfa->edests[node_idx].elems[0]
+ : dfa->eclosures + dfa->nexts[node_idx]);
+ dest_str_idx = (cur_str_idx + bkref_ent->subexp_to
+ - bkref_ent->subexp_from);
+ context = re_string_context_at (&mctx->input, dest_str_idx - 1,
+ mctx->eflags);
+ dest_state = mctx->state_log[dest_str_idx];
+ prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0
+ : mctx->state_log[cur_str_idx]->nodes.nelem);
+ /* Add `new_dest_node' to state_log. */
+ if (dest_state == NULL)
+ {
+ mctx->state_log[dest_str_idx]
+ = re_acquire_state_context (&err, dfa, new_dest_nodes,
+ context);
+ if (BE (mctx->state_log[dest_str_idx] == NULL
+ && err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ else
+ {
+ re_node_set dest_nodes;
+ err = re_node_set_init_union (&dest_nodes,
+ dest_state->entrance_nodes,
+ new_dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&dest_nodes);
+ goto free_return;
+ }
+ mctx->state_log[dest_str_idx]
+ = re_acquire_state_context (&err, dfa, &dest_nodes, context);
+ re_node_set_free (&dest_nodes);
+ if (BE (mctx->state_log[dest_str_idx] == NULL
+ && err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ /* We need to check recursively if the backreference can epsilon
+ transit. */
+ if (subexp_len == 0
+ && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem)
+ {
+ err = check_subexp_matching_top (mctx, new_dest_nodes,
+ cur_str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ err = transit_state_bkref (mctx, new_dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ }
+ }
+ err = REG_NOERROR;
+ free_return:
+ return err;
+}
+
+/* Enumerate all the candidates which the backreference BKREF_NODE can match
+ at BKREF_STR_IDX, and register them by match_ctx_add_entry().
+ Note that we might collect inappropriate candidates here.
+ However, the cost of checking them strictly here is too high, then we
+ delay these checking for prune_impossible_nodes(). */
+
+static reg_errcode_t
+get_subexp (mctx, bkref_node, bkref_str_idx)
+ re_match_context_t *mctx;
+ int bkref_node, bkref_str_idx;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ int subexp_num, sub_top_idx;
+ const char *buf = (const char *) re_string_get_buffer (&mctx->input);
+ /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */
+ int cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx);
+ if (cache_idx != -1)
+ {
+ const struct re_backref_cache_entry *entry = mctx->bkref_ents + cache_idx;
+ do
+ if (entry->node == bkref_node)
+ return REG_NOERROR; /* We already checked it. */
+ while (entry++->more);
+ }
+
+ subexp_num = dfa->nodes[bkref_node].opr.idx;
+
+ /* For each sub expression */
+ for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx)
+ {
+ reg_errcode_t err;
+ re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx];
+ re_sub_match_last_t *sub_last;
+ int sub_last_idx, sl_str, bkref_str_off;
+
+ if (dfa->nodes[sub_top->node].opr.idx != subexp_num)
+ continue; /* It isn't related. */
+
+ sl_str = sub_top->str_idx;
+ bkref_str_off = bkref_str_idx;
+ /* At first, check the last node of sub expressions we already
+ evaluated. */
+ for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx)
+ {
+ int sl_str_diff;
+ sub_last = sub_top->lasts[sub_last_idx];
+ sl_str_diff = sub_last->str_idx - sl_str;
+ /* The matched string by the sub expression match with the substring
+ at the back reference? */
+ if (sl_str_diff > 0)
+ {
+ if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0))
+ {
+ /* Not enough chars for a successful match. */
+ if (bkref_str_off + sl_str_diff > mctx->input.len)
+ break;
+
+ err = clean_state_log_if_needed (mctx,
+ bkref_str_off
+ + sl_str_diff);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+ }
+ if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0)
+ break; /* We don't need to search this sub expression any more. */
+ }
+ bkref_str_off += sl_str_diff;
+ sl_str += sl_str_diff;
+ err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
+ bkref_str_idx);
+
+ /* Reload buf, since the preceding call might have reallocated
+ the buffer. */
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+
+ if (err == REG_NOMATCH)
+ continue;
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (sub_last_idx < sub_top->nlasts)
+ continue;
+ if (sub_last_idx > 0)
+ ++sl_str;
+ /* Then, search for the other last nodes of the sub expression. */
+ for (; sl_str <= bkref_str_idx; ++sl_str)
+ {
+ int cls_node, sl_str_off;
+ const re_node_set *nodes;
+ sl_str_off = sl_str - sub_top->str_idx;
+ /* The matched string by the sub expression match with the substring
+ at the back reference? */
+ if (sl_str_off > 0)
+ {
+ if (BE (bkref_str_off >= mctx->input.valid_len, 0))
+ {
+ /* If we are at the end of the input, we cannot match. */
+ if (bkref_str_off >= mctx->input.len)
+ break;
+
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+ }
+ if (buf [bkref_str_off++] != buf[sl_str - 1])
+ break; /* We don't need to search this sub expression
+ any more. */
+ }
+ if (mctx->state_log[sl_str] == NULL)
+ continue;
+ /* Does this state have a ')' of the sub expression? */
+ nodes = &mctx->state_log[sl_str]->nodes;
+ cls_node = find_subexp_node (dfa, nodes, subexp_num, OP_CLOSE_SUBEXP);
+ if (cls_node == -1)
+ continue; /* No. */
+ if (sub_top->path == NULL)
+ {
+ sub_top->path = calloc (sizeof (state_array_t),
+ sl_str - sub_top->str_idx + 1);
+ if (sub_top->path == NULL)
+ return REG_ESPACE;
+ }
+ /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node
+ in the current context? */
+ err = check_arrival (mctx, sub_top->path, sub_top->node,
+ sub_top->str_idx, cls_node, sl_str, OP_CLOSE_SUBEXP);
+ if (err == REG_NOMATCH)
+ continue;
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str);
+ if (BE (sub_last == NULL, 0))
+ return REG_ESPACE;
+ err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
+ bkref_str_idx);
+ if (err == REG_NOMATCH)
+ continue;
+ }
+ }
+ return REG_NOERROR;
+}
+
+/* Helper functions for get_subexp(). */
+
+/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR.
+ If it can arrive, register the sub expression expressed with SUB_TOP
+ and SUB_LAST. */
+
+static reg_errcode_t
+get_subexp_sub (mctx, sub_top, sub_last, bkref_node, bkref_str)
+ re_match_context_t *mctx;
+ const re_sub_match_top_t *sub_top;
+ re_sub_match_last_t *sub_last;
+ int bkref_node, bkref_str;
+{
+ reg_errcode_t err;
+ int to_idx;
+ /* Can the subexpression arrive the back reference? */
+ err = check_arrival (mctx, &sub_last->path, sub_last->node,
+ sub_last->str_idx, bkref_node, bkref_str, OP_OPEN_SUBEXP);
+ if (err != REG_NOERROR)
+ return err;
+ err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx,
+ sub_last->str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx;
+ return clean_state_log_if_needed (mctx, to_idx);
+}
+
+/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX.
+ Search '(' if FL_OPEN, or search ')' otherwise.
+ TODO: This function isn't efficient...
+ Because there might be more than one nodes whose types are
+ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
+ nodes.
+ E.g. RE: (a){2} */
+
+static int
+find_subexp_node (dfa, nodes, subexp_idx, type)
+ const re_dfa_t *dfa;
+ const re_node_set *nodes;
+ int subexp_idx, type;
+{
+ int cls_idx;
+ for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx)
+ {
+ int cls_node = nodes->elems[cls_idx];
+ const re_token_t *node = dfa->nodes + cls_node;
+ if (node->type == type
+ && node->opr.idx == subexp_idx)
+ return cls_node;
+ }
+ return -1;
+}
+
+/* Check whether the node TOP_NODE at TOP_STR can arrive to the node
+ LAST_NODE at LAST_STR. We record the path onto PATH since it will be
+ heavily reused.
+ Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */
+
+static reg_errcode_t
+check_arrival (mctx, path, top_node, top_str, last_node, last_str,
+ type)
+ re_match_context_t *mctx;
+ state_array_t *path;
+ int top_node, top_str, last_node, last_str, type;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int subexp_num, backup_cur_idx, str_idx, null_cnt;
+ re_dfastate_t *cur_state = NULL;
+ re_node_set *cur_nodes, next_nodes;
+ re_dfastate_t **backup_state_log;
+ unsigned int context;
+
+ subexp_num = dfa->nodes[top_node].opr.idx;
+ /* Extend the buffer if we need. */
+ if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0))
+ {
+ re_dfastate_t **new_array;
+ int old_alloc = path->alloc;
+ path->alloc += last_str + mctx->max_mb_elem_len + 1;
+ new_array = re_realloc (path->array, re_dfastate_t *, path->alloc);
+ if (new_array == NULL)
+ {
+ path->alloc = old_alloc;
+ return REG_ESPACE;
+ }
+ path->array = new_array;
+ memset (new_array + old_alloc, '\0',
+ sizeof (re_dfastate_t *) * (path->alloc - old_alloc));
+ }
+
+ str_idx = path->next_idx == 0 ? top_str : path->next_idx;
+
+ /* Temporary modify MCTX. */
+ backup_state_log = mctx->state_log;
+ backup_cur_idx = mctx->input.cur_idx;
+ mctx->state_log = path->array;
+ mctx->input.cur_idx = str_idx;
+
+ /* Setup initial node set. */
+ context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
+ if (str_idx == top_str)
+ {
+ err = re_node_set_init_1 (&next_nodes, top_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ else
+ {
+ cur_state = mctx->state_log[str_idx];
+ if (cur_state && cur_state->has_backref)
+ {
+ err = re_node_set_init_copy (&next_nodes, &cur_state->nodes);
+ if (BE ( err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ re_node_set_init_empty (&next_nodes);
+ }
+ if (str_idx == top_str || (cur_state && cur_state->has_backref))
+ {
+ if (next_nodes.nelem)
+ {
+ err = expand_bkref_cache (mctx, &next_nodes, str_idx,
+ subexp_num, type);
+ if (BE ( err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
+ if (BE (cur_state == NULL && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ mctx->state_log[str_idx] = cur_state;
+ }
+
+ for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;)
+ {
+ re_node_set_empty (&next_nodes);
+ if (mctx->state_log[str_idx + 1])
+ {
+ err = re_node_set_merge (&next_nodes,
+ &mctx->state_log[str_idx + 1]->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ if (cur_state)
+ {
+ err = check_arrival_add_next_nodes (mctx, str_idx,
+ &cur_state->non_eps_nodes, &next_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ ++str_idx;
+ if (next_nodes.nelem)
+ {
+ err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ err = expand_bkref_cache (mctx, &next_nodes, str_idx,
+ subexp_num, type);
+ if (BE ( err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
+ cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
+ if (BE (cur_state == NULL && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ mctx->state_log[str_idx] = cur_state;
+ null_cnt = cur_state == NULL ? null_cnt + 1 : 0;
+ }
+ re_node_set_free (&next_nodes);
+ cur_nodes = (mctx->state_log[last_str] == NULL ? NULL
+ : &mctx->state_log[last_str]->nodes);
+ path->next_idx = str_idx;
+
+ /* Fix MCTX. */
+ mctx->state_log = backup_state_log;
+ mctx->input.cur_idx = backup_cur_idx;
+
+ /* Then check the current node set has the node LAST_NODE. */
+ if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node))
+ return REG_NOERROR;
+
+ return REG_NOMATCH;
+}
+
+/* Helper functions for check_arrival. */
+
+/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them
+ to NEXT_NODES.
+ TODO: This function is similar to the functions transit_state*(),
+ however this function has many additional works.
+ Can't we unify them? */
+
+static reg_errcode_t
+check_arrival_add_next_nodes (mctx, str_idx, cur_nodes, next_nodes)
+ re_match_context_t *mctx;
+ int str_idx;
+ re_node_set *cur_nodes, *next_nodes;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ int result;
+ int cur_idx;
+ reg_errcode_t err;
+ re_node_set union_set;
+ re_node_set_init_empty (&union_set);
+ for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx)
+ {
+ int naccepted = 0;
+ int cur_node = cur_nodes->elems[cur_idx];
+#ifdef DEBUG
+ re_token_type_t type = dfa->nodes[cur_node].type;
+ assert (!IS_EPSILON_NODE (type));
+#endif
+#ifdef RE_ENABLE_I18N
+ /* If the node may accept `multi byte'. */
+ if (dfa->nodes[cur_node].accept_mb)
+ {
+ naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input,
+ str_idx);
+ if (naccepted > 1)
+ {
+ re_dfastate_t *dest_state;
+ int next_node = dfa->nexts[cur_node];
+ int next_idx = str_idx + naccepted;
+ dest_state = mctx->state_log[next_idx];
+ re_node_set_empty (&union_set);
+ if (dest_state)
+ {
+ err = re_node_set_merge (&union_set, &dest_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&union_set);
+ return err;
+ }
+ }
+ result = re_node_set_insert (&union_set, next_node);
+ if (BE (result < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ return REG_ESPACE;
+ }
+ mctx->state_log[next_idx] = re_acquire_state (&err, dfa,
+ &union_set);
+ if (BE (mctx->state_log[next_idx] == NULL
+ && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&union_set);
+ return err;
+ }
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ if (naccepted
+ || check_node_accept (mctx, dfa->nodes + cur_node, str_idx))
+ {
+ result = re_node_set_insert (next_nodes, dfa->nexts[cur_node]);
+ if (BE (result < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ return REG_ESPACE;
+ }
+ }
+ }
+ re_node_set_free (&union_set);
+ return REG_NOERROR;
+}
+
+/* For all the nodes in CUR_NODES, add the epsilon closures of them to
+ CUR_NODES, however exclude the nodes which are:
+ - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN.
+ - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN.
+*/
+
+static reg_errcode_t
+check_arrival_expand_ecl (dfa, cur_nodes, ex_subexp, type)
+ re_dfa_t *dfa;
+ re_node_set *cur_nodes;
+ int ex_subexp, type;
+{
+ reg_errcode_t err;
+ int idx, outside_node;
+ re_node_set new_nodes;
+#ifdef DEBUG
+ assert (cur_nodes->nelem);
+#endif
+ err = re_node_set_alloc (&new_nodes, cur_nodes->nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ /* Create a new node set NEW_NODES with the nodes which are epsilon
+ closures of the node in CUR_NODES. */
+
+ for (idx = 0; idx < cur_nodes->nelem; ++idx)
+ {
+ int cur_node = cur_nodes->elems[idx];
+ re_node_set *eclosure = dfa->eclosures + cur_node;
+ outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type);
+ if (outside_node == -1)
+ {
+ /* There are no problematic nodes, just merge them. */
+ err = re_node_set_merge (&new_nodes, eclosure);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&new_nodes);
+ return err;
+ }
+ }
+ else
+ {
+ /* There are problematic nodes, re-calculate incrementally. */
+ err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node,
+ ex_subexp, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&new_nodes);
+ return err;
+ }
+ }
+ }
+ re_node_set_free (cur_nodes);
+ *cur_nodes = new_nodes;
+ return REG_NOERROR;
+}
+
+/* Helper function for check_arrival_expand_ecl.
+ Check incrementally the epsilon closure of TARGET, and if it isn't
+ problematic append it to DST_NODES. */
+
+static reg_errcode_t
+check_arrival_expand_ecl_sub (dfa, dst_nodes, target, ex_subexp, type)
+ re_dfa_t *dfa;
+ int target, ex_subexp, type;
+ re_node_set *dst_nodes;
+{
+ int cur_node;
+ for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);)
+ {
+ int err;
+
+ if (dfa->nodes[cur_node].type == type
+ && dfa->nodes[cur_node].opr.idx == ex_subexp)
+ {
+ if (type == OP_CLOSE_SUBEXP)
+ {
+ err = re_node_set_insert (dst_nodes, cur_node);
+ if (BE (err == -1, 0))
+ return REG_ESPACE;
+ }
+ break;
+ }
+ err = re_node_set_insert (dst_nodes, cur_node);
+ if (BE (err == -1, 0))
+ return REG_ESPACE;
+ if (dfa->edests[cur_node].nelem == 0)
+ break;
+ if (dfa->edests[cur_node].nelem == 2)
+ {
+ err = check_arrival_expand_ecl_sub (dfa, dst_nodes,
+ dfa->edests[cur_node].elems[1],
+ ex_subexp, type);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ cur_node = dfa->edests[cur_node].elems[0];
+ }
+ return REG_NOERROR;
+}
+
+
+/* For all the back references in the current state, calculate the
+ destination of the back references by the appropriate entry
+ in MCTX->BKREF_ENTS. */
+
+static reg_errcode_t
+expand_bkref_cache (mctx, cur_nodes, cur_str, subexp_num,
+ type)
+ re_match_context_t *mctx;
+ int cur_str, subexp_num, type;
+ re_node_set *cur_nodes;
+{
+ re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int cache_idx_start = search_cur_bkref_entry (mctx, cur_str);
+ struct re_backref_cache_entry *ent;
+
+ if (cache_idx_start == -1)
+ return REG_NOERROR;
+
+ restart:
+ ent = mctx->bkref_ents + cache_idx_start;
+ do
+ {
+ int to_idx, next_node;
+
+ /* Is this entry ENT is appropriate? */
+ if (!re_node_set_contains (cur_nodes, ent->node))
+ continue; /* No. */
+
+ to_idx = cur_str + ent->subexp_to - ent->subexp_from;
+ /* Calculate the destination of the back reference, and append it
+ to MCTX->STATE_LOG. */
+ if (to_idx == cur_str)
+ {
+ /* The backreference did epsilon transit, we must re-check all the
+ node in the current state. */
+ re_node_set new_dests;
+ reg_errcode_t err2, err3;
+ next_node = dfa->edests[ent->node].elems[0];
+ if (re_node_set_contains (cur_nodes, next_node))
+ continue;
+ err = re_node_set_init_1 (&new_dests, next_node);
+ err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type);
+ err3 = re_node_set_merge (cur_nodes, &new_dests);
+ re_node_set_free (&new_dests);
+ if (BE (err != REG_NOERROR || err2 != REG_NOERROR
+ || err3 != REG_NOERROR, 0))
+ {
+ err = (err != REG_NOERROR ? err
+ : (err2 != REG_NOERROR ? err2 : err3));
+ return err;
+ }
+ /* TODO: It is still inefficient... */
+ goto restart;
+ }
+ else
+ {
+ re_node_set union_set;
+ next_node = dfa->nexts[ent->node];
+ if (mctx->state_log[to_idx])
+ {
+ int ret;
+ if (re_node_set_contains (&mctx->state_log[to_idx]->nodes,
+ next_node))
+ continue;
+ err = re_node_set_init_copy (&union_set,
+ &mctx->state_log[to_idx]->nodes);
+ ret = re_node_set_insert (&union_set, next_node);
+ if (BE (err != REG_NOERROR || ret < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ err = err != REG_NOERROR ? err : REG_ESPACE;
+ return err;
+ }
+ }
+ else
+ {
+ err = re_node_set_init_1 (&union_set, next_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set);
+ re_node_set_free (&union_set);
+ if (BE (mctx->state_log[to_idx] == NULL
+ && err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ while (ent++->more);
+ return REG_NOERROR;
+}
+
+/* Build transition table for the state.
+ Return 1 if succeeded, otherwise return NULL. */
+
+static int
+build_trtable (dfa, state)
+ re_dfa_t *dfa;
+ re_dfastate_t *state;
+{
+ reg_errcode_t err;
+ int i, j, ch, need_word_trtable = 0;
+ unsigned int elem, mask;
+ int dests_node_malloced = 0, dest_states_malloced = 0;
+ int ndests; /* Number of the destination states from `state'. */
+ re_dfastate_t **trtable;
+ re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl;
+ re_node_set follows, *dests_node;
+ bitset *dests_ch;
+ bitset acceptable;
+
+ /* We build DFA states which corresponds to the destination nodes
+ from `state'. `dests_node[i]' represents the nodes which i-th
+ destination state contains, and `dests_ch[i]' represents the
+ characters which i-th destination state accepts. */
+#ifdef _LIBC
+ if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX))
+ dests_node = (re_node_set *)
+ alloca ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX);
+ else
+#endif
+ {
+ dests_node = (re_node_set *)
+ malloc ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX);
+ if (BE (dests_node == NULL, 0))
+ return 0;
+ dests_node_malloced = 1;
+ }
+ dests_ch = (bitset *) (dests_node + SBC_MAX);
+
+ /* Initialize transiton table. */
+ state->word_trtable = state->trtable = NULL;
+
+ /* At first, group all nodes belonging to `state' into several
+ destinations. */
+ ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch);
+ if (BE (ndests <= 0, 0))
+ {
+ if (dests_node_malloced)
+ free (dests_node);
+ /* Return 0 in case of an error, 1 otherwise. */
+ if (ndests == 0)
+ {
+ state->trtable = (re_dfastate_t **)
+ calloc (sizeof (re_dfastate_t *), SBC_MAX);
+ return 1;
+ }
+ return 0;
+ }
+
+ err = re_node_set_alloc (&follows, ndests + 1);
+ if (BE (err != REG_NOERROR, 0))
+ goto out_free;
+
+#ifdef _LIBC
+ if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX
+ + ndests * 3 * sizeof (re_dfastate_t *)))
+ dest_states = (re_dfastate_t **)
+ alloca (ndests * 3 * sizeof (re_dfastate_t *));
+ else
+#endif
+ {
+ dest_states = (re_dfastate_t **)
+ malloc (ndests * 3 * sizeof (re_dfastate_t *));
+ if (BE (dest_states == NULL, 0))
+ {
+out_free:
+ if (dest_states_malloced)
+ free (dest_states);
+ re_node_set_free (&follows);
+ for (i = 0; i < ndests; ++i)
+ re_node_set_free (dests_node + i);
+ if (dests_node_malloced)
+ free (dests_node);
+ return 0;
+ }
+ dest_states_malloced = 1;
+ }
+ dest_states_word = dest_states + ndests;
+ dest_states_nl = dest_states_word + ndests;
+ bitset_empty (acceptable);
+
+ /* Then build the states for all destinations. */
+ for (i = 0; i < ndests; ++i)
+ {
+ int next_node;
+ re_node_set_empty (&follows);
+ /* Merge the follows of this destination states. */
+ for (j = 0; j < dests_node[i].nelem; ++j)
+ {
+ next_node = dfa->nexts[dests_node[i].elems[j]];
+ if (next_node != -1)
+ {
+ err = re_node_set_merge (&follows, dfa->eclosures + next_node);
+ if (BE (err != REG_NOERROR, 0))
+ goto out_free;
+ }
+ }
+ dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0);
+ if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+ /* If the new state has context constraint,
+ build appropriate states for these contexts. */
+ if (dest_states[i]->has_constraint)
+ {
+ dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows,
+ CONTEXT_WORD);
+ if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+
+ if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1)
+ need_word_trtable = 1;
+
+ dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
+ CONTEXT_NEWLINE);
+ if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+ }
+ else
+ {
+ dest_states_word[i] = dest_states[i];
+ dest_states_nl[i] = dest_states[i];
+ }
+ bitset_merge (acceptable, dests_ch[i]);
+ }
+
+ if (!BE (need_word_trtable, 0))
+ {
+ /* We don't care about whether the following character is a word
+ character, or we are in a single-byte character set so we can
+ discern by looking at the character code: allocate a
+ 256-entry transition table. */
+ trtable = state->trtable =
+ (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX);
+ if (BE (trtable == NULL, 0))
+ goto out_free;
+
+ /* For all characters ch...: */
+ for (i = 0; i < BITSET_UINTS; ++i)
+ for (ch = i * UINT_BITS, elem = acceptable[i], mask = 1;
+ elem;
+ mask <<= 1, elem >>= 1, ++ch)
+ if (BE (elem & 1, 0))
+ {
+ /* There must be exactly one destination which accepts
+ character ch. See group_nodes_into_DFAstates. */
+ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
+ ;
+
+ /* j-th destination accepts the word character ch. */
+ if (dfa->word_char[i] & mask)
+ trtable[ch] = dest_states_word[j];
+ else
+ trtable[ch] = dest_states[j];
+ }
+ }
+ else
+ {
+ /* We care about whether the following character is a word
+ character, and we are in a multi-byte character set: discern
+ by looking at the character code: build two 256-entry
+ transition tables, one starting at trtable[0] and one
+ starting at trtable[SBC_MAX]. */
+ trtable = state->word_trtable =
+ (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX);
+ if (BE (trtable == NULL, 0))
+ goto out_free;
+
+ /* For all characters ch...: */
+ for (i = 0; i < BITSET_UINTS; ++i)
+ for (ch = i * UINT_BITS, elem = acceptable[i], mask = 1;
+ elem;
+ mask <<= 1, elem >>= 1, ++ch)
+ if (BE (elem & 1, 0))
+ {
+ /* There must be exactly one destination which accepts
+ character ch. See group_nodes_into_DFAstates. */
+ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
+ ;
+
+ /* j-th destination accepts the word character ch. */
+ trtable[ch] = dest_states[j];
+ trtable[ch + SBC_MAX] = dest_states_word[j];
+ }
+ }
+
+ /* new line */
+ if (bitset_contain (acceptable, NEWLINE_CHAR))
+ {
+ /* The current state accepts newline character. */
+ for (j = 0; j < ndests; ++j)
+ if (bitset_contain (dests_ch[j], NEWLINE_CHAR))
+ {
+ /* k-th destination accepts newline character. */
+ trtable[NEWLINE_CHAR] = dest_states_nl[j];
+ if (need_word_trtable)
+ trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j];
+ /* There must be only one destination which accepts
+ newline. See group_nodes_into_DFAstates. */
+ break;
+ }
+ }
+
+ if (dest_states_malloced)
+ free (dest_states);
+
+ re_node_set_free (&follows);
+ for (i = 0; i < ndests; ++i)
+ re_node_set_free (dests_node + i);
+
+ if (dests_node_malloced)
+ free (dests_node);
+
+ return 1;
+}
+
+/* Group all nodes belonging to STATE into several destinations.
+ Then for all destinations, set the nodes belonging to the destination
+ to DESTS_NODE[i] and set the characters accepted by the destination
+ to DEST_CH[i]. This function return the number of destinations. */
+
+static int
+group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch)
+ re_dfa_t *dfa;
+ const re_dfastate_t *state;
+ re_node_set *dests_node;
+ bitset *dests_ch;
+{
+ reg_errcode_t err;
+ int result;
+ int i, j, k;
+ int ndests; /* Number of the destinations from `state'. */
+ bitset accepts; /* Characters a node can accept. */
+ const re_node_set *cur_nodes = &state->nodes;
+ bitset_empty (accepts);
+ ndests = 0;
+
+ /* For all the nodes belonging to `state', */
+ for (i = 0; i < cur_nodes->nelem; ++i)
+ {
+ re_token_t *node = &dfa->nodes[cur_nodes->elems[i]];
+ re_token_type_t type = node->type;
+ unsigned int constraint = node->constraint;
+
+ /* Enumerate all single byte character this node can accept. */
+ if (type == CHARACTER)
+ bitset_set (accepts, node->opr.c);
+ else if (type == SIMPLE_BRACKET)
+ {
+ bitset_merge (accepts, node->opr.sbcset);
+ }
+ else if (type == OP_PERIOD)
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ bitset_merge (accepts, dfa->sb_char);
+ else
+#endif
+ bitset_set_all (accepts);
+ if (!(dfa->syntax & RE_DOT_NEWLINE))
+ bitset_clear (accepts, '\n');
+ if (dfa->syntax & RE_DOT_NOT_NULL)
+ bitset_clear (accepts, '\0');
+ }
+#ifdef RE_ENABLE_I18N
+ else if (type == OP_UTF8_PERIOD)
+ {
+ memset (accepts, 255, sizeof (unsigned int) * BITSET_UINTS / 2);
+ if (!(dfa->syntax & RE_DOT_NEWLINE))
+ bitset_clear (accepts, '\n');
+ if (dfa->syntax & RE_DOT_NOT_NULL)
+ bitset_clear (accepts, '\0');
+ }
+#endif
+ else
+ continue;
+
+ /* Check the `accepts' and sift the characters which are not
+ match it the context. */
+ if (constraint)
+ {
+ if (constraint & NEXT_NEWLINE_CONSTRAINT)
+ {
+ int accepts_newline = bitset_contain (accepts, NEWLINE_CHAR);
+ bitset_empty (accepts);
+ if (accepts_newline)
+ bitset_set (accepts, NEWLINE_CHAR);
+ else
+ continue;
+ }
+ if (constraint & NEXT_ENDBUF_CONSTRAINT)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+
+ if (constraint & NEXT_WORD_CONSTRAINT)
+ {
+ unsigned int any_set = 0;
+ if (type == CHARACTER && !node->word_char)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ for (j = 0; j < BITSET_UINTS; ++j)
+ any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
+ else
+#endif
+ for (j = 0; j < BITSET_UINTS; ++j)
+ any_set |= (accepts[j] &= dfa->word_char[j]);
+ if (!any_set)
+ continue;
+ }
+ if (constraint & NEXT_NOTWORD_CONSTRAINT)
+ {
+ unsigned int any_set = 0;
+ if (type == CHARACTER && node->word_char)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ for (j = 0; j < BITSET_UINTS; ++j)
+ any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
+ else
+#endif
+ for (j = 0; j < BITSET_UINTS; ++j)
+ any_set |= (accepts[j] &= ~dfa->word_char[j]);
+ if (!any_set)
+ continue;
+ }
+ }
+
+ /* Then divide `accepts' into DFA states, or create a new
+ state. Above, we make sure that accepts is not empty. */
+ for (j = 0; j < ndests; ++j)
+ {
+ bitset intersec; /* Intersection sets, see below. */
+ bitset remains;
+ /* Flags, see below. */
+ int has_intersec, not_subset, not_consumed;
+
+ /* Optimization, skip if this state doesn't accept the character. */
+ if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c))
+ continue;
+
+ /* Enumerate the intersection set of this state and `accepts'. */
+ has_intersec = 0;
+ for (k = 0; k < BITSET_UINTS; ++k)
+ has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k];
+ /* And skip if the intersection set is empty. */
+ if (!has_intersec)
+ continue;
+
+ /* Then check if this state is a subset of `accepts'. */
+ not_subset = not_consumed = 0;
+ for (k = 0; k < BITSET_UINTS; ++k)
+ {
+ not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k];
+ not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k];
+ }
+
+ /* If this state isn't a subset of `accepts', create a
+ new group state, which has the `remains'. */
+ if (not_subset)
+ {
+ bitset_copy (dests_ch[ndests], remains);
+ bitset_copy (dests_ch[j], intersec);
+ err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]);
+ if (BE (err != REG_NOERROR, 0))
+ goto error_return;
+ ++ndests;
+ }
+
+ /* Put the position in the current group. */
+ result = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]);
+ if (BE (result < 0, 0))
+ goto error_return;
+
+ /* If all characters are consumed, go to next node. */
+ if (!not_consumed)
+ break;
+ }
+ /* Some characters remain, create a new group. */
+ if (j == ndests)
+ {
+ bitset_copy (dests_ch[ndests], accepts);
+ err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]);
+ if (BE (err != REG_NOERROR, 0))
+ goto error_return;
+ ++ndests;
+ bitset_empty (accepts);
+ }
+ }
+ return ndests;
+ error_return:
+ for (j = 0; j < ndests; ++j)
+ re_node_set_free (dests_node + j);
+ return -1;
+}
+
+#ifdef RE_ENABLE_I18N
+/* Check how many bytes the node `dfa->nodes[node_idx]' accepts.
+ Return the number of the bytes the node accepts.
+ STR_IDX is the current index of the input string.
+
+ This function handles the nodes which can accept one character, or
+ one collating element like '.', '[a-z]', opposite to the other nodes
+ can only accept one byte. */
+
+static int
+check_node_accept_bytes (dfa, node_idx, input, str_idx)
+ re_dfa_t *dfa;
+ int node_idx, str_idx;
+ const re_string_t *input;
+{
+ const re_token_t *node = dfa->nodes + node_idx;
+ int char_len, elem_len;
+ int i;
+
+ if (BE (node->type == OP_UTF8_PERIOD, 0))
+ {
+ unsigned char c = re_string_byte_at (input, str_idx), d;
+ if (BE (c < 0xc2, 1))
+ return 0;
+
+ if (str_idx + 2 > input->len)
+ return 0;
+
+ d = re_string_byte_at (input, str_idx + 1);
+ if (c < 0xe0)
+ return (d < 0x80 || d > 0xbf) ? 0 : 2;
+ else if (c < 0xf0)
+ {
+ char_len = 3;
+ if (c == 0xe0 && d < 0xa0)
+ return 0;
+ }
+ else if (c < 0xf8)
+ {
+ char_len = 4;
+ if (c == 0xf0 && d < 0x90)
+ return 0;
+ }
+ else if (c < 0xfc)
+ {
+ char_len = 5;
+ if (c == 0xf8 && d < 0x88)
+ return 0;
+ }
+ else if (c < 0xfe)
+ {
+ char_len = 6;
+ if (c == 0xfc && d < 0x84)
+ return 0;
+ }
+ else
+ return 0;
+
+ if (str_idx + char_len > input->len)
+ return 0;
+
+ for (i = 1; i < char_len; ++i)
+ {
+ d = re_string_byte_at (input, str_idx + i);
+ if (d < 0x80 || d > 0xbf)
+ return 0;
+ }
+ return char_len;
+ }
+
+ char_len = re_string_char_size_at (input, str_idx);
+ if (node->type == OP_PERIOD)
+ {
+ if (char_len <= 1)
+ return 0;
+ /* FIXME: I don't think this if is needed, as both '\n'
+ and '\0' are char_len == 1. */
+ /* '.' accepts any one character except the following two cases. */
+ if ((!(dfa->syntax & RE_DOT_NEWLINE) &&
+ re_string_byte_at (input, str_idx) == '\n') ||
+ ((dfa->syntax & RE_DOT_NOT_NULL) &&
+ re_string_byte_at (input, str_idx) == '\0'))
+ return 0;
+ return char_len;
+ }
+
+ elem_len = re_string_elem_size_at (input, str_idx);
+ if ((elem_len <= 1 && char_len <= 1) || char_len == 0)
+ return 0;
+
+ if (node->type == COMPLEX_BRACKET)
+ {
+ const re_charset_t *cset = node->opr.mbcset;
+# ifdef _LIBC
+ const unsigned char *pin
+ = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
+ int j;
+ uint32_t nrules;
+# endif /* _LIBC */
+ int match_len = 0;
+ wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
+ ? re_string_wchar_at (input, str_idx) : 0);
+
+ /* match with multibyte character? */
+ for (i = 0; i < cset->nmbchars; ++i)
+ if (wc == cset->mbchars[i])
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ /* match with character_class? */
+ for (i = 0; i < cset->nchar_classes; ++i)
+ {
+ wctype_t wt = cset->char_classes[i];
+ if (__iswctype (wc, wt))
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+
+# ifdef _LIBC
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+ unsigned int in_collseq = 0;
+ const int32_t *table, *indirect;
+ const unsigned char *weights, *extra;
+ const char *collseqwc;
+ int32_t idx;
+ /* This #include defines a local function! */
+# include <locale/weight.h>
+
+ /* match with collating_symbol? */
+ if (cset->ncoll_syms)
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+ for (i = 0; i < cset->ncoll_syms; ++i)
+ {
+ const unsigned char *coll_sym = extra + cset->coll_syms[i];
+ /* Compare the length of input collating element and
+ the length of current collating element. */
+ if (*coll_sym != elem_len)
+ continue;
+ /* Compare each bytes. */
+ for (j = 0; j < *coll_sym; j++)
+ if (pin[j] != coll_sym[1 + j])
+ break;
+ if (j == *coll_sym)
+ {
+ /* Match if every bytes is equal. */
+ match_len = j;
+ goto check_node_accept_bytes_match;
+ }
+ }
+
+ if (cset->nranges)
+ {
+ if (elem_len <= char_len)
+ {
+ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ in_collseq = __collseq_table_lookup (collseqwc, wc);
+ }
+ else
+ in_collseq = find_collation_sequence_value (pin, elem_len);
+ }
+ /* match with range expression? */
+ for (i = 0; i < cset->nranges; ++i)
+ if (cset->range_starts[i] <= in_collseq
+ && in_collseq <= cset->range_ends[i])
+ {
+ match_len = elem_len;
+ goto check_node_accept_bytes_match;
+ }
+
+ /* match with equivalence_class? */
+ if (cset->nequiv_classes)
+ {
+ const unsigned char *cp = pin;
+ table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ weights = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
+ idx = findidx (&cp);
+ if (idx > 0)
+ for (i = 0; i < cset->nequiv_classes; ++i)
+ {
+ int32_t equiv_class_idx = cset->equiv_classes[i];
+ size_t weight_len = weights[idx];
+ if (weight_len == weights[equiv_class_idx])
+ {
+ int cnt = 0;
+ while (cnt <= weight_len
+ && (weights[equiv_class_idx + 1 + cnt]
+ == weights[idx + 1 + cnt]))
+ ++cnt;
+ if (cnt > weight_len)
+ {
+ match_len = elem_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+ }
+ }
+ }
+ else
+# endif /* _LIBC */
+ {
+ /* match with range expression? */
+#if __GNUC__ >= 2
+ wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'};
+#else
+ wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
+ cmp_buf[2] = wc;
+#endif
+ for (i = 0; i < cset->nranges; ++i)
+ {
+ cmp_buf[0] = cset->range_starts[i];
+ cmp_buf[4] = cset->range_ends[i];
+ if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
+ && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+ }
+ check_node_accept_bytes_match:
+ if (!cset->non_match)
+ return match_len;
+ else
+ {
+ if (match_len > 0)
+ return 0;
+ else
+ return (elem_len > char_len) ? elem_len : char_len;
+ }
+ }
+ return 0;
+}
+
+# ifdef _LIBC
+static unsigned int
+find_collation_sequence_value (mbs, mbs_len)
+ const unsigned char *mbs;
+ size_t mbs_len;
+{
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules == 0)
+ {
+ if (mbs_len == 1)
+ {
+ /* No valid character. Match it as a single byte character. */
+ const unsigned char *collseq = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ return collseq[mbs[0]];
+ }
+ return UINT_MAX;
+ }
+ else
+ {
+ int32_t idx;
+ const unsigned char *extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+ int32_t extrasize = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra;
+
+ for (idx = 0; idx < extrasize;)
+ {
+ int mbs_cnt, found = 0;
+ int32_t elem_mbs_len;
+ /* Skip the name of collating element name. */
+ idx = idx + extra[idx] + 1;
+ elem_mbs_len = extra[idx++];
+ if (mbs_len == elem_mbs_len)
+ {
+ for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt)
+ if (extra[idx + mbs_cnt] != mbs[mbs_cnt])
+ break;
+ if (mbs_cnt == elem_mbs_len)
+ /* Found the entry. */
+ found = 1;
+ }
+ /* Skip the byte sequence of the collating element. */
+ idx += elem_mbs_len;
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+ /* Skip the collation sequence value. */
+ idx += sizeof (uint32_t);
+ /* Skip the wide char sequence of the collating element. */
+ idx = idx + sizeof (uint32_t) * (extra[idx] + 1);
+ /* If we found the entry, return the sequence value. */
+ if (found)
+ return *(uint32_t *) (extra + idx);
+ /* Skip the collation sequence value. */
+ idx += sizeof (uint32_t);
+ }
+ return UINT_MAX;
+ }
+}
+# endif /* _LIBC */
+#endif /* RE_ENABLE_I18N */
+
+/* Check whether the node accepts the byte which is IDX-th
+ byte of the INPUT. */
+
+static int
+check_node_accept (mctx, node, idx)
+ const re_match_context_t *mctx;
+ const re_token_t *node;
+ int idx;
+{
+ unsigned char ch;
+ ch = re_string_byte_at (&mctx->input, idx);
+ switch (node->type)
+ {
+ case CHARACTER:
+ if (node->opr.c != ch)
+ return 0;
+ break;
+
+ case SIMPLE_BRACKET:
+ if (!bitset_contain (node->opr.sbcset, ch))
+ return 0;
+ break;
+
+#ifdef RE_ENABLE_I18N
+ case OP_UTF8_PERIOD:
+ if (ch >= 0x80)
+ return 0;
+ /* FALLTHROUGH */
+#endif
+ case OP_PERIOD:
+ if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE))
+ || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL)))
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (node->constraint)
+ {
+ /* The node has constraints. Check whether the current context
+ satisfies the constraints. */
+ unsigned int context = re_string_context_at (&mctx->input, idx,
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Extend the buffers, if the buffers have run out. */
+
+static reg_errcode_t
+extend_buffers (mctx)
+ re_match_context_t *mctx;
+{
+ reg_errcode_t ret;
+ re_string_t *pstr = &mctx->input;
+
+ /* Double the lengthes of the buffers. */
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ if (mctx->state_log != NULL)
+ {
+ /* And double the length of state_log. */
+ /* XXX We have no indication of the size of this buffer. If this
+ allocation fail we have no indication that the state_log array
+ does not have the right size. */
+ re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *,
+ pstr->bufs_len + 1);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ mctx->state_log = new_array;
+ }
+
+ /* Then reconstruct the buffers. */
+ if (pstr->icase)
+ {
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ build_upper_buffer (pstr);
+ }
+ else
+ {
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ build_wcs_buffer (pstr);
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ if (pstr->trans != NULL)
+ re_string_translate_buffer (pstr);
+ }
+ }
+ return REG_NOERROR;
+}
+
+
+/* Functions for matching context. */
+
+/* Initialize MCTX. */
+
+static reg_errcode_t
+match_ctx_init (mctx, eflags, n)
+ re_match_context_t *mctx;
+ int eflags, n;
+{
+ mctx->eflags = eflags;
+ mctx->match_last = -1;
+ if (n > 0)
+ {
+ mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n);
+ mctx->sub_tops = re_malloc (re_sub_match_top_t *, n);
+ if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0))
+ return REG_ESPACE;
+ }
+ /* Already zero-ed by the caller.
+ else
+ mctx->bkref_ents = NULL;
+ mctx->nbkref_ents = 0;
+ mctx->nsub_tops = 0; */
+ mctx->abkref_ents = n;
+ mctx->max_mb_elem_len = 1;
+ mctx->asub_tops = n;
+ return REG_NOERROR;
+}
+
+/* Clean the entries which depend on the current input in MCTX.
+ This function must be invoked when the matcher changes the start index
+ of the input, or changes the input string. */
+
+static void
+match_ctx_clean (mctx)
+ re_match_context_t *mctx;
+{
+ int st_idx;
+ for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx)
+ {
+ int sl_idx;
+ re_sub_match_top_t *top = mctx->sub_tops[st_idx];
+ for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx)
+ {
+ re_sub_match_last_t *last = top->lasts[sl_idx];
+ re_free (last->path.array);
+ re_free (last);
+ }
+ re_free (top->lasts);
+ if (top->path)
+ {
+ re_free (top->path->array);
+ re_free (top->path);
+ }
+ free (top);
+ }
+
+ mctx->nsub_tops = 0;
+ mctx->nbkref_ents = 0;
+}
+
+/* Free all the memory associated with MCTX. */
+
+static void
+match_ctx_free (mctx)
+ re_match_context_t *mctx;
+{
+ /* First, free all the memory associated with MCTX->SUB_TOPS. */
+ match_ctx_clean (mctx);
+ re_free (mctx->sub_tops);
+ re_free (mctx->bkref_ents);
+}
+
+/* Add a new backreference entry to MCTX.
+ Note that we assume that caller never call this function with duplicate
+ entry, and call with STR_IDX which isn't smaller than any existing entry.
+*/
+
+static reg_errcode_t
+match_ctx_add_entry (mctx, node, str_idx, from, to)
+ re_match_context_t *mctx;
+ int node, str_idx, from, to;
+{
+ if (mctx->nbkref_ents >= mctx->abkref_ents)
+ {
+ struct re_backref_cache_entry* new_entry;
+ new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry,
+ mctx->abkref_ents * 2);
+ if (BE (new_entry == NULL, 0))
+ {
+ re_free (mctx->bkref_ents);
+ return REG_ESPACE;
+ }
+ mctx->bkref_ents = new_entry;
+ memset (mctx->bkref_ents + mctx->nbkref_ents, '\0',
+ sizeof (struct re_backref_cache_entry) * mctx->abkref_ents);
+ mctx->abkref_ents *= 2;
+ }
+ if (mctx->nbkref_ents > 0
+ && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx)
+ mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1;
+
+ mctx->bkref_ents[mctx->nbkref_ents].node = node;
+ mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx;
+ mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from;
+ mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to;
+
+ /* This is a cache that saves negative results of check_dst_limits_calc_pos.
+ If bit N is clear, means that this entry won't epsilon-transition to
+ an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If
+ it is set, check_dst_limits_calc_pos_1 will recurse and try to find one
+ such node.
+
+ A backreference does not epsilon-transition unless it is empty, so set
+ to all zeros if FROM != TO. */
+ mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map
+ = (from == to ? ~0 : 0);
+
+ mctx->bkref_ents[mctx->nbkref_ents++].more = 0;
+ if (mctx->max_mb_elem_len < to - from)
+ mctx->max_mb_elem_len = to - from;
+ return REG_NOERROR;
+}
+
+/* Search for the first entry which has the same str_idx, or -1 if none is
+ found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */
+
+static int
+search_cur_bkref_entry (mctx, str_idx)
+ re_match_context_t *mctx;
+ int str_idx;
+{
+ int left, right, mid, last;
+ last = right = mctx->nbkref_ents;
+ for (left = 0; left < right;)
+ {
+ mid = (left + right) / 2;
+ if (mctx->bkref_ents[mid].str_idx < str_idx)
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ if (left < last && mctx->bkref_ents[left].str_idx == str_idx)
+ return left;
+ else
+ return -1;
+}
+
+/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches
+ at STR_IDX. */
+
+static reg_errcode_t
+match_ctx_add_subtop (mctx, node, str_idx)
+ re_match_context_t *mctx;
+ int node, str_idx;
+{
+#ifdef DEBUG
+ assert (mctx->sub_tops != NULL);
+ assert (mctx->asub_tops > 0);
+#endif
+ if (BE (mctx->nsub_tops == mctx->asub_tops, 0))
+ {
+ int new_asub_tops = mctx->asub_tops * 2;
+ re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops,
+ re_sub_match_top_t *,
+ new_asub_tops);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ mctx->sub_tops = new_array;
+ mctx->asub_tops = new_asub_tops;
+ }
+ mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t));
+ if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0))
+ return REG_ESPACE;
+ mctx->sub_tops[mctx->nsub_tops]->node = node;
+ mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx;
+ return REG_NOERROR;
+}
+
+/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches
+ at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */
+
+static re_sub_match_last_t *
+match_ctx_add_sublast (subtop, node, str_idx)
+ re_sub_match_top_t *subtop;
+ int node, str_idx;
+{
+ re_sub_match_last_t *new_entry;
+ if (BE (subtop->nlasts == subtop->alasts, 0))
+ {
+ int new_alasts = 2 * subtop->alasts + 1;
+ re_sub_match_last_t **new_array = re_realloc (subtop->lasts,
+ re_sub_match_last_t *,
+ new_alasts);
+ if (BE (new_array == NULL, 0))
+ return NULL;
+ subtop->lasts = new_array;
+ subtop->alasts = new_alasts;
+ }
+ new_entry = calloc (1, sizeof (re_sub_match_last_t));
+ if (BE (new_entry != NULL, 1))
+ {
+ subtop->lasts[subtop->nlasts] = new_entry;
+ new_entry->node = node;
+ new_entry->str_idx = str_idx;
+ ++subtop->nlasts;
+ }
+ return new_entry;
+}
+
+static void
+sift_ctx_init (sctx, sifted_sts, limited_sts, last_node, last_str_idx)
+ re_sift_context_t *sctx;
+ re_dfastate_t **sifted_sts, **limited_sts;
+ int last_node, last_str_idx;
+{
+ sctx->sifted_states = sifted_sts;
+ sctx->limited_states = limited_sts;
+ sctx->last_node = last_node;
+ sctx->last_str_idx = last_str_idx;
+ re_node_set_init_empty (&sctx->limits);
+}
diff --git a/gnu/lib/libssp/Makefile b/gnu/lib/libssp/Makefile
new file mode 100644
index 0000000..641874c
--- /dev/null
+++ b/gnu/lib/libssp/Makefile
@@ -0,0 +1,38 @@
+# $FreeBSD$
+
+SHLIBDIR?= /lib
+
+.include <bsd.own.mk>
+MK_SSP= no
+
+GCCDIR= ${.CURDIR}/../../../contrib/gcc
+GCCLIB= ${.CURDIR}/../../../contrib/gcclibs
+SRCDIR= ${GCCLIB}/libssp
+
+.PATH: ${SRCDIR} ${SRCDIR}/ssp
+
+LIB= ssp
+SHLIB_MAJOR= 0
+NO_PROFILE=
+
+SRCS= ssp.c gets-chk.c memcpy-chk.c memmove-chk.c mempcpy-chk.c \
+ memset-chk.c snprintf-chk.c sprintf-chk.c stpcpy-chk.c \
+ strcat-chk.c strcpy-chk.c strncat-chk.c strncpy-chk.c \
+ vsnprintf-chk.c vsprintf-chk.c
+
+CFLAGS+= -DHAVE_CONFIG_H
+CFLAGS+= -I${.CURDIR} -I${SRCDIR} -I${GCCLIB}/include
+
+VERSION_MAP= ${SRCDIR}/ssp.map
+
+
+INCS= ssp.h string.h stdio.h unistd.h
+INCSDIR=${INCLUDEDIR}/ssp
+
+CLEANFILES= ssp.h
+ssp.h: ssp.h.in
+ sed -e 's/@ssp_have_usable_vsnprintf@/define/' ${.ALLSRC} > ${.TARGET}
+
+SUBDIR+= libssp_nonshared
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libssp/config.h b/gnu/lib/libssp/config.h
new file mode 100644
index 0000000..680f107
--- /dev/null
+++ b/gnu/lib/libssp/config.h
@@ -0,0 +1,87 @@
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+/* $FreeBSD$ */
+
+/* Define to 1 if you have the <alloca.h> header file. */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* __attribute__((visibility ("hidden"))) supported */
+#define HAVE_HIDDEN_VISIBILITY 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mempcpy' function. */
+/* #undef HAVE_MEMPCPY */
+
+/* Define to 1 if you have the <paths.h> header file. */
+#define HAVE_PATHS_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strncat' function. */
+#define HAVE_STRNCAT 1
+
+/* Define to 1 if you have the `strncpy' function. */
+#define HAVE_STRNCPY 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* vsnprintf is present and works */
+#define HAVE_USABLE_VSNPRINTF 1
+
+/* Name of package */
+#define PACKAGE "libssp"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libssp"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libssp 1.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libssp"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.0"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "1.0"
diff --git a/gnu/lib/libssp/libssp_nonshared/Makefile b/gnu/lib/libssp/libssp_nonshared/Makefile
new file mode 100644
index 0000000..9454495
--- /dev/null
+++ b/gnu/lib/libssp/libssp_nonshared/Makefile
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+GCCDIR= ${.CURDIR}/../../../../contrib/gcc
+GCCLIB= ${.CURDIR}/../../../../contrib/gcclibs
+
+.PATH: ${GCCLIB}/libssp ${GCCLIB}/libssp/ssp
+
+LIB= ssp_nonshared
+NO_PIC=
+NO_PROFILE=
+
+SRCS= ssp-local.c
+
+CFLAGS+= -DHAVE_CONFIG_H
+CFLAGS+= -I${.CURDIR}/.. -I${GCCLIB}/libssp -I${GCCLIB}/include
+CFLAGS+= -fPIC -DPIC -fvisibility=hidden
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libstdc++/Makefile b/gnu/lib/libstdc++/Makefile
new file mode 100644
index 0000000..56ca626
--- /dev/null
+++ b/gnu/lib/libstdc++/Makefile
@@ -0,0 +1,627 @@
+# $FreeBSD$
+
+GCCVER= 4.2
+GCCDIR= ${.CURDIR}/../../../contrib/gcc
+GCCLIB= ${.CURDIR}/../../../contrib/gcclibs
+SRCDIR= ${.CURDIR}/../../../contrib/libstdc++
+SUPDIR= ${SRCDIR}/libsupc++
+
+.PATH: ${SRCDIR}/src ${SRCDIR}/libmath ${SRCDIR}/config/io \
+ ${SRCDIR}/config/locale/darwin ${SRCDIR}/config/locale/generic \
+ ${SRCDIR}/include ${SUPDIR} ${GCCDIR} ${GCCLIB}/libiberty
+
+LIB= stdc++
+SHLIB_MAJOR= 6
+
+CFLAGS+= -DIN_GLIBCPP_V3 -DHAVE_CONFIG_H
+.if ${MACHINE_CPUARCH} == "arm"
+CFLAGS+= -D_GLIBCXX_SJLJ_EXCEPTIONS=1
+.endif
+CFLAGS+= -I${.CURDIR} -I${SUPDIR} -I${GCCDIR} -I${SRCDIR}/include
+CFLAGS+= -I${GCCLIB}/include -I${SRCDIR}/include -I.
+CFLAGS+= -frandom-seed=RepeatabilityConsideredGood
+CXXFLAGS+= -fno-implicit-templates -ffunction-sections -fdata-sections \
+ -Wno-deprecated
+PO_CXXFLAGS= ${CXXFLAGS:N-ffunction-sections}
+
+DPADD= ${LIBM}
+LDADD= -lm
+
+# libstdc++ sources
+SRCS+= bitmap_allocator.cc pool_allocator.cc \
+ mt_allocator.cc codecvt.cc compatibility.cc complex_io.cc \
+ ctype.cc debug.cc debug_list.cc functexcept.cc globals_io.cc \
+ ios.cc ios_failure.cc ios_init.cc ios_locale.cc limits.cc \
+ list.cc locale.cc locale_init.cc locale_facets.cc \
+ localename.cc stdexcept.cc strstream.cc tree.cc \
+ allocator-inst.cc concept-inst.cc fstream-inst.cc ext-inst.cc \
+ ios-inst.cc iostream-inst.cc istream-inst.cc istream.cc \
+ locale-inst.cc misc-inst.cc ostream-inst.cc sstream-inst.cc \
+ streambuf-inst.cc streambuf.cc string-inst.cc valarray-inst.cc \
+ wlocale-inst.cc wstring-inst.cc atomicity.cc \
+ codecvt_members.cc collate_members.cc ctype_members.cc \
+ messages_members.cc monetary_members.cc numeric_members.cc \
+ time_members.cc basic_file_stdio.cc c_locale.cc \
+# compatibility-ldbl.cc
+
+# target sources
+SRCS+= atomicity.cc codecvt_members.cc collate_members.cc ctype_members.cc \
+ messages_members.cc monetary_members.cc numeric_members.cc \
+ time_members.cc
+
+# target sources extra
+SRCS+= basic_file_stdio.cc c_locale.cc
+
+# C parts of math
+SRCS+= stubs.c
+
+# Embedded copy of libsupc++
+SRCS+= del_op.cc del_opnt.cc del_opv.cc del_opvnt.cc eh_alloc.cc eh_arm.cc \
+ eh_aux_runtime.cc eh_call.cc eh_catch.cc eh_exception.cc eh_globals.cc \
+ eh_personality.cc eh_term_handler.cc eh_terminate.cc eh_throw.cc \
+ eh_type.cc eh_unex_handler.cc guard.cc new_handler.cc new_op.cc \
+ new_opnt.cc new_opv.cc new_opvnt.cc pure.cc tinfo.cc tinfo2.cc \
+ vec.cc vterminate.cc
+
+# from libiberty:
+SRCS+= cp-demangle.c
+
+# MD headers location
+.if ${MACHINE_CPUARCH} == "sparc64"
+MARCHDIR= sparc
+.elif ${MACHINE_CPUARCH} == "i386" && ${MACHINE_CPU} != 'i386'
+MARCHDIR= i486
+.elif ${MACHINE_CPUARCH} == "amd64"
+MARCHDIR= i486
+.else
+MARCHDIR= ${MACHINE_CPUARCH}
+.endif
+
+.if exists(${SRCDIR}/config/cpu/${MARCHDIR}/atomicity.h)
+ATOMICITY_H= ${SRCDIR}/config/cpu/${MARCHDIR}/atomicity.h
+.else
+ATOMICITY_H= ${SRCDIR}/config/cpu/generic/atomicity_mutex/atomicity.h
+.endif
+
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
+.if exists(${SRCDIR}/config/cpu/generic/atomicity_builtins/atomicity.h)
+ATOMICITY_H= ${SRCDIR}/config/cpu/generic/atomicity_builtins/atomicity.h
+.endif
+.endif
+
+atomicity.cc: ${ATOMICITY_H}
+ ln -sf ${.ALLSRC} ${.TARGET}
+CLEANFILES+= atomicity.cc
+
+INCSGROUPS= BITSHDRS BKWHDRS EXTHDRS BASEHDRS BASEXHDRS STDHDRS \
+ TARGETHDRS THRHDRS DEBUGHDRS TR1HDRS PBHDRS0 PBHDRS1
+CXXINCLUDEDIR= ${INCLUDEDIR}/c++/${GCCVER}
+
+STDHDRS= std_algorithm.h std_bitset.h std_complex.h std_deque.h \
+ std_fstream.h std_functional.h std_iomanip.h std_ios.h \
+ std_iosfwd.h std_iostream.h std_istream.h std_iterator.h \
+ std_limits.h std_list.h std_locale.h std_map.h std_memory.h \
+ std_numeric.h std_ostream.h std_queue.h std_set.h \
+ std_sstream.h std_stack.h std_stdexcept.h std_streambuf.h \
+ std_string.h std_utility.h std_valarray.h std_vector.h
+.for h in ${STDHDRS}
+STDHDRSNAME_$h=${h:R:S;^std_;;}
+.endfor
+STDHDRS:= ${STDHDRS:S;^;${SRCDIR}/include/std/;}
+STDHDRSDIR= ${CXXINCLUDEDIR}
+
+BITSHDRS= allocator.h basic_ios.h basic_ios.tcc basic_string.h \
+ basic_string.tcc boost_concept_check.h char_traits.h codecvt.h \
+ concept_check.h cpp_type_traits.h deque.tcc fstream.tcc \
+ functexcept.h gslice.h gslice_array.h indirect_array.h \
+ ios_base.h istream.tcc list.tcc locale_classes.h \
+ locale_facets.h locale_facets.tcc localefwd.h mask_array.h \
+ ostream.tcc ostream_insert.h postypes.h stream_iterator.h \
+ streambuf_iterator.h slice_array.h sstream.tcc stl_algo.h \
+ stl_algobase.h stl_bvector.h stl_construct.h stl_deque.h \
+ stl_function.h stl_heap.h stl_iterator.h \
+ stl_iterator_base_funcs.h stl_iterator_base_types.h stl_list.h \
+ stl_map.h stl_multimap.h stl_multiset.h stl_numeric.h \
+ stl_pair.h stl_queue.h stl_raw_storage_iter.h stl_relops.h \
+ stl_set.h stl_stack.h stl_tempbuf.h stl_tree.h \
+ stl_uninitialized.h stl_vector.h streambuf.tcc stringfwd.h \
+ valarray_array.h valarray_array.tcc valarray_before.h \
+ valarray_after.h vector.tcc
+BITSHDRS:= ${BITSHDRS:S;^;${SRCDIR}/include/bits/;}
+BITSHDRSDIR= ${CXXINCLUDEDIR}/bits
+
+BKWHDRS= complex.h iomanip.h istream.h ostream.h stream.h streambuf.h \
+ algo.h algobase.h alloc.h bvector.h defalloc.h deque.h \
+ function.h hash_map.h hash_set.h hashtable.h heap.h iostream.h \
+ iterator.h list.h map.h multimap.h new.h multiset.h pair.h \
+ queue.h rope.h set.h slist.h stack.h tempbuf.h tree.h \
+ vector.h fstream.h strstream backward_warning.h
+BKWHDRS:= ${BKWHDRS:S;^;${SRCDIR}/include/backward/;}
+BKWHDRSDIR= ${CXXINCLUDEDIR}/backward
+
+EXTHDRS= algorithm atomicity.h array_allocator.h bitmap_allocator.h \
+ codecvt_specializations.h concurrence.h debug_allocator.h \
+ stdio_filebuf.h stdio_sync_filebuf.h functional \
+ hash_map hash_set hash_fun.h hashtable.h iterator \
+ malloc_allocator.h memory mt_allocator.h new_allocator.h \
+ numeric numeric_traits.h pod_char_traits.h pool_allocator.h \
+ rb_tree rope ropeimpl.h slist throw_allocator.h typelist.h \
+ type_traits.h rc_string_base.h sso_string_base.h vstring.h \
+ vstring.tcc vstring_fwd.h vstring_util.h
+
+EXTHDRS:= ${EXTHDRS:S;^;${SRCDIR}/include/ext/;}
+EXTHDRSDIR= ${CXXINCLUDEDIR}/ext
+
+TR1HDRS= array bind_repeat.h bind_iterate.h boost_shared_ptr.h cctype \
+ cfenv cfloat cinttypes climits cmath common.h complex cstdarg \
+ cstdbool cstdint cstdio cstdlib ctgmath ctime ctype.h cwchar \
+ cwctype fenv.h float.h functional functional_hash.h \
+ functional_iterate.h hashtable hashtable_policy.h inttypes.h \
+ limits.h math.h memory mu_iterate.h random random.tcc \
+ ref_fwd.h ref_wrap_iterate.h repeat.h stdarg.h stdbool.h \
+ stdint.h stdio.h stdlib.h tgmath.h tuple tuple_defs.h \
+ tuple_iterate.h type_traits type_traits_fwd.h unordered_set \
+ unordered_map utility wchar.h wctype.h
+
+TR1HDRS:= ${TR1HDRS:S;^;${SRCDIR}/include/tr1/;}
+TR1HDRSDIR= ${CXXINCLUDEDIR}/tr1
+
+# This is the common subset of files that all three "C" header models use.
+BASEHDRS= std_cassert.h std_cctype.h std_cerrno.h std_cfloat.h \
+ std_ciso646.h std_climits.h std_clocale.h std_cmath.h \
+ std_csetjmp.h std_csignal.h std_cstdarg.h std_cstddef.h \
+ std_cstdio.h std_cstdlib.h std_cstring.h std_ctime.h \
+ std_cwchar.h std_cwctype.h
+.for h in ${BASEHDRS}
+BASEHDRSNAME_$h=${h:R:S;^std_;;}
+.endfor
+BASEHDRS:= ${BASEHDRS:S;^;${SRCDIR}/include/c_std/;}
+BASEHDRSDIR= ${CXXINCLUDEDIR}
+
+# Some of the different "C" header models need extra files.
+BASEXHDRS= ${SRCDIR}/include/c_std/cmath.tcc
+BASEXHDRSDIR= ${CXXINCLUDEDIR}/bits
+
+DEBUGHDRS= bitset debug.h deque formatter.h functions.h hash_map \
+ hash_map.h hash_multimap.h hash_multiset.h hash_set hash_set.h \
+ list macros.h map map.h multimap.h multiset.h safe_base.h \
+ safe_iterator.h safe_iterator.tcc safe_sequence.h set set.h \
+ string vector
+DEBUGHDRS:= ${DEBUGHDRS:S;^;${SRCDIR}/include/debug/;}
+DEBUGHDRSDIR= ${CXXINCLUDEDIR}/debug
+
+# Not installed, but kept here for completeness
+COMPATHDRS= assert.h ctype.h errno.h float.h iso646.h limits.h locale.h \
+ math.h setjmp.h signal.h stdarg.h stddef.h stdio.h stdlib.h \
+ string.h time.h wchar.h wctype.h
+COMPATHDRS:= ${COMPATHDRS:S;^;${SRCDIR}/include/debug/;}
+COMPATHDRSDIR= ${CXXINCLUDEDIR}/c_compatibility
+
+PBHDRS0 = \
+ assoc_container.hpp \
+ exception.hpp \
+ hash_policy.hpp \
+ list_update_policy.hpp \
+ priority_queue.hpp \
+ tag_and_trait.hpp \
+ tree_policy.hpp \
+ trie_policy.hpp
+PBHDRS0:= ${PBHDRS0:S;^;${SRCDIR}/include/ext/pb_ds/;}
+PBHDRS0DIR= ${CXXINCLUDEDIR}/ext/pb_ds
+
+PBHDRS1 = \
+ basic_types.hpp \
+ cond_dealtor.hpp \
+ constructors_destructor_fn_imps.hpp \
+ container_base_dispatch.hpp \
+ map_debug_base.hpp \
+ priority_queue_base_dispatch.hpp \
+ standard_policies.hpp \
+ tree_trace_base.hpp \
+ type_utils.hpp \
+ types_traits.hpp
+PBHDRS1:= ${PBHDRS1:S;^;${SRCDIR}/include/ext/pb_ds/detail/;}
+PBHDRS1DIR= ${CXXINCLUDEDIR}/ext/pb_ds/detail
+
+PBHDRS+= \
+ basic_tree_policy/basic_tree_policy_base.hpp \
+ basic_tree_policy/null_node_metadata.hpp \
+ basic_tree_policy/traits.hpp \
+ basic_types.hpp \
+ binary_heap_/binary_heap_.hpp \
+ binary_heap_/const_iterator.hpp \
+ binary_heap_/const_point_iterator.hpp \
+ binary_heap_/constructors_destructor_fn_imps.hpp \
+ binary_heap_/debug_fn_imps.hpp \
+ binary_heap_/entry_cmp.hpp \
+ binary_heap_/entry_pred.hpp \
+ binary_heap_/erase_fn_imps.hpp \
+ binary_heap_/find_fn_imps.hpp \
+ binary_heap_/info_fn_imps.hpp \
+ binary_heap_/insert_fn_imps.hpp \
+ binary_heap_/iterators_fn_imps.hpp \
+ binary_heap_/policy_access_fn_imps.hpp \
+ binary_heap_/resize_policy.hpp \
+ binary_heap_/split_join_fn_imps.hpp \
+ binary_heap_/trace_fn_imps.hpp \
+ binomial_heap_base_/binomial_heap_base_.hpp \
+ binomial_heap_base_/constructors_destructor_fn_imps.hpp \
+ binomial_heap_base_/debug_fn_imps.hpp \
+ binomial_heap_base_/erase_fn_imps.hpp \
+ binomial_heap_base_/find_fn_imps.hpp \
+ binomial_heap_base_/insert_fn_imps.hpp \
+ binomial_heap_base_/split_join_fn_imps.hpp \
+ binomial_heap_/binomial_heap_.hpp \
+ binomial_heap_/constructors_destructor_fn_imps.hpp \
+ binomial_heap_/debug_fn_imps.hpp \
+ bin_search_tree_/bin_search_tree_.hpp \
+ bin_search_tree_/cond_dtor_entry_dealtor.hpp \
+ bin_search_tree_/cond_key_dtor_entry_dealtor.hpp
+
+PBHDRS+= \
+ bin_search_tree_/constructors_destructor_fn_imps.hpp \
+ bin_search_tree_/debug_fn_imps.hpp \
+ bin_search_tree_/erase_fn_imps.hpp \
+ bin_search_tree_/find_fn_imps.hpp \
+ bin_search_tree_/info_fn_imps.hpp \
+ bin_search_tree_/insert_fn_imps.hpp \
+ bin_search_tree_/iterators_fn_imps.hpp \
+ bin_search_tree_/node_iterators.hpp \
+ bin_search_tree_/point_iterators.hpp \
+ bin_search_tree_/policy_access_fn_imps.hpp \
+ bin_search_tree_/r_erase_fn_imps.hpp \
+ bin_search_tree_/rotate_fn_imps.hpp \
+ bin_search_tree_/split_join_fn_imps.hpp \
+ bin_search_tree_/traits.hpp \
+ cc_hash_table_map_/cc_ht_map_.hpp \
+ cc_hash_table_map_/cmp_fn_imps.hpp \
+ cc_hash_table_map_/cond_key_dtor_entry_dealtor.hpp \
+ cc_hash_table_map_/constructor_destructor_fn_imps.hpp \
+ cc_hash_table_map_/constructor_destructor_no_store_hash_fn_imps.hpp \
+ cc_hash_table_map_/constructor_destructor_store_hash_fn_imps.hpp \
+ cc_hash_table_map_/debug_fn_imps.hpp \
+ cc_hash_table_map_/debug_no_store_hash_fn_imps.hpp \
+ cc_hash_table_map_/debug_store_hash_fn_imps.hpp \
+ cc_hash_table_map_/entry_list_fn_imps.hpp \
+ cc_hash_table_map_/erase_fn_imps.hpp \
+ cc_hash_table_map_/erase_no_store_hash_fn_imps.hpp \
+ cc_hash_table_map_/erase_store_hash_fn_imps.hpp \
+ cc_hash_table_map_/find_fn_imps.hpp \
+ cc_hash_table_map_/find_store_hash_fn_imps.hpp \
+ cc_hash_table_map_/info_fn_imps.hpp \
+ cc_hash_table_map_/insert_fn_imps.hpp \
+ cc_hash_table_map_/insert_no_store_hash_fn_imps.hpp \
+ cc_hash_table_map_/insert_store_hash_fn_imps.hpp \
+ cc_hash_table_map_/iterators_fn_imps.hpp \
+ cc_hash_table_map_/policy_access_fn_imps.hpp \
+ cc_hash_table_map_/resize_fn_imps.hpp \
+ cc_hash_table_map_/resize_no_store_hash_fn_imps.hpp \
+ cc_hash_table_map_/resize_store_hash_fn_imps.hpp \
+ cc_hash_table_map_/size_fn_imps.hpp \
+ cc_hash_table_map_/standard_policies.hpp
+
+PBHDRS+= \
+ cc_hash_table_map_/trace_fn_imps.hpp \
+ cond_dealtor.hpp \
+ constructors_destructor_fn_imps.hpp \
+ container_base_dispatch.hpp \
+ eq_fn/eq_by_less.hpp \
+ eq_fn/hash_eq_fn.hpp \
+ gp_hash_table_map_/constructor_destructor_fn_imps.hpp \
+ gp_hash_table_map_/constructor_destructor_no_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/constructor_destructor_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/debug_fn_imps.hpp \
+ gp_hash_table_map_/debug_no_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/debug_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/erase_fn_imps.hpp \
+ gp_hash_table_map_/erase_no_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/erase_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/find_fn_imps.hpp \
+ gp_hash_table_map_/find_no_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/find_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/gp_ht_map_.hpp \
+ gp_hash_table_map_/info_fn_imps.hpp \
+ gp_hash_table_map_/insert_fn_imps.hpp \
+ gp_hash_table_map_/insert_no_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/insert_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/iterator_fn_imps.hpp \
+ gp_hash_table_map_/policy_access_fn_imps.hpp \
+ gp_hash_table_map_/resize_fn_imps.hpp \
+ gp_hash_table_map_/resize_no_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/resize_store_hash_fn_imps.hpp \
+ gp_hash_table_map_/standard_policies.hpp \
+ gp_hash_table_map_/trace_fn_imps.hpp \
+ hash_fn/direct_mask_range_hashing_imp.hpp \
+ hash_fn/direct_mod_range_hashing_imp.hpp \
+ hash_fn/linear_probe_fn_imp.hpp \
+ hash_fn/mask_based_range_hashing.hpp \
+ hash_fn/mod_based_range_hashing.hpp \
+ hash_fn/probe_fn_base.hpp \
+ hash_fn/quadratic_probe_fn_imp.hpp \
+ hash_fn/ranged_hash_fn.hpp \
+ hash_fn/ranged_probe_fn.hpp
+
+PBHDRS+= \
+ hash_fn/sample_probe_fn.hpp \
+ hash_fn/sample_ranged_hash_fn.hpp \
+ hash_fn/sample_ranged_probe_fn.hpp \
+ hash_fn/sample_range_hashing.hpp \
+ left_child_next_sibling_heap_/const_iterator.hpp \
+ left_child_next_sibling_heap_/const_point_iterator.hpp \
+ left_child_next_sibling_heap_/constructors_destructor_fn_imps.hpp \
+ left_child_next_sibling_heap_/debug_fn_imps.hpp \
+ left_child_next_sibling_heap_/erase_fn_imps.hpp \
+ left_child_next_sibling_heap_/info_fn_imps.hpp \
+ left_child_next_sibling_heap_/insert_fn_imps.hpp \
+ left_child_next_sibling_heap_/iterators_fn_imps.hpp \
+ left_child_next_sibling_heap_/left_child_next_sibling_heap_.hpp \
+ left_child_next_sibling_heap_/node.hpp \
+ left_child_next_sibling_heap_/null_metadata.hpp \
+ left_child_next_sibling_heap_/policy_access_fn_imps.hpp \
+ left_child_next_sibling_heap_/trace_fn_imps.hpp \
+ list_update_map_/constructor_destructor_fn_imps.hpp \
+ list_update_map_/debug_fn_imps.hpp \
+ list_update_map_/entry_metadata_base.hpp \
+ list_update_map_/erase_fn_imps.hpp \
+ list_update_map_/find_fn_imps.hpp \
+ list_update_map_/info_fn_imps.hpp \
+ list_update_map_/insert_fn_imps.hpp \
+ list_update_map_/iterators_fn_imps.hpp \
+ list_update_map_/lu_map_.hpp \
+ list_update_map_/trace_fn_imps.hpp \
+ list_update_policy/counter_lu_metadata.hpp \
+ list_update_policy/counter_lu_policy_imp.hpp \
+ list_update_policy/mtf_lu_policy_imp.hpp \
+ list_update_policy/sample_update_policy.hpp \
+ map_debug_base.hpp \
+ ov_tree_map_/cond_dtor.hpp \
+ ov_tree_map_/constructors_destructor_fn_imps.hpp \
+ ov_tree_map_/debug_fn_imps.hpp \
+ ov_tree_map_/erase_fn_imps.hpp \
+ ov_tree_map_/info_fn_imps.hpp \
+ ov_tree_map_/insert_fn_imps.hpp \
+ ov_tree_map_/iterators_fn_imps.hpp \
+ ov_tree_map_/node_iterators.hpp \
+ ov_tree_map_/ov_tree_map_.hpp
+
+PBHDRS+= \
+ ov_tree_map_/policy_access_fn_imps.hpp \
+ ov_tree_map_/split_join_fn_imps.hpp \
+ ov_tree_map_/traits.hpp \
+ pairing_heap_/constructors_destructor_fn_imps.hpp \
+ pairing_heap_/debug_fn_imps.hpp \
+ pairing_heap_/erase_fn_imps.hpp \
+ pairing_heap_/find_fn_imps.hpp \
+ pairing_heap_/insert_fn_imps.hpp \
+ pairing_heap_/pairing_heap_.hpp \
+ pairing_heap_/split_join_fn_imps.hpp \
+ pat_trie_/child_iterator.hpp \
+ pat_trie_/cond_dtor_entry_dealtor.hpp \
+ pat_trie_/const_child_iterator.hpp \
+ pat_trie_/constructors_destructor_fn_imps.hpp \
+ pat_trie_/debug_fn_imps.hpp \
+ pat_trie_/erase_fn_imps.hpp \
+ pat_trie_/find_fn_imps.hpp \
+ pat_trie_/head.hpp \
+ pat_trie_/info_fn_imps.hpp \
+ pat_trie_/insert_join_fn_imps.hpp \
+ pat_trie_/internal_node.hpp \
+ pat_trie_/iterators_fn_imps.hpp \
+ pat_trie_/leaf.hpp \
+ pat_trie_/node_base.hpp \
+ pat_trie_/node_iterators.hpp \
+ pat_trie_/node_metadata_base.hpp \
+ pat_trie_/pat_trie_.hpp \
+ pat_trie_/point_iterators.hpp \
+ pat_trie_/policy_access_fn_imps.hpp \
+ pat_trie_/r_erase_fn_imps.hpp \
+ pat_trie_/rotate_fn_imps.hpp \
+ pat_trie_/split_fn_imps.hpp \
+ pat_trie_/split_join_branch_bag.hpp \
+ pat_trie_/synth_e_access_traits.hpp \
+ pat_trie_/trace_fn_imps.hpp \
+ pat_trie_/traits.hpp \
+ pat_trie_/update_fn_imps.hpp \
+ priority_queue_base_dispatch.hpp \
+ rb_tree_map_/constructors_destructor_fn_imps.hpp \
+ rb_tree_map_/debug_fn_imps.hpp
+
+PBHDRS+= \
+ rb_tree_map_/erase_fn_imps.hpp \
+ rb_tree_map_/find_fn_imps.hpp \
+ rb_tree_map_/info_fn_imps.hpp \
+ rb_tree_map_/insert_fn_imps.hpp \
+ rb_tree_map_/node.hpp \
+ rb_tree_map_/rb_tree_.hpp \
+ rb_tree_map_/split_join_fn_imps.hpp \
+ rb_tree_map_/traits.hpp \
+ rc_binomial_heap_/constructors_destructor_fn_imps.hpp \
+ rc_binomial_heap_/debug_fn_imps.hpp \
+ rc_binomial_heap_/erase_fn_imps.hpp \
+ rc_binomial_heap_/insert_fn_imps.hpp \
+ rc_binomial_heap_/rc_binomial_heap_.hpp \
+ rc_binomial_heap_/rc.hpp \
+ rc_binomial_heap_/split_join_fn_imps.hpp \
+ rc_binomial_heap_/trace_fn_imps.hpp \
+ resize_policy/cc_hash_max_collision_check_resize_trigger_imp.hpp \
+ resize_policy/hash_exponential_size_policy_imp.hpp \
+ resize_policy/hash_load_check_resize_trigger_imp.hpp \
+ resize_policy/hash_load_check_resize_trigger_size_base.hpp \
+ resize_policy/hash_prime_size_policy_imp.hpp \
+ resize_policy/hash_standard_resize_policy_imp.hpp \
+ resize_policy/sample_resize_policy.hpp \
+ resize_policy/sample_resize_trigger.hpp \
+ resize_policy/sample_size_policy.hpp \
+ splay_tree_/constructors_destructor_fn_imps.hpp \
+ splay_tree_/debug_fn_imps.hpp \
+ splay_tree_/erase_fn_imps.hpp \
+ splay_tree_/find_fn_imps.hpp \
+ splay_tree_/info_fn_imps.hpp \
+ splay_tree_/insert_fn_imps.hpp \
+ splay_tree_/node.hpp \
+ splay_tree_/splay_fn_imps.hpp \
+ splay_tree_/splay_tree_.hpp \
+ splay_tree_/split_join_fn_imps.hpp \
+ splay_tree_/traits.hpp \
+ standard_policies.hpp \
+ thin_heap_/constructors_destructor_fn_imps.hpp \
+ thin_heap_/debug_fn_imps.hpp \
+ thin_heap_/erase_fn_imps.hpp
+
+PBHDRS+= \
+ thin_heap_/find_fn_imps.hpp \
+ thin_heap_/insert_fn_imps.hpp \
+ thin_heap_/split_join_fn_imps.hpp \
+ thin_heap_/thin_heap_.hpp \
+ thin_heap_/trace_fn_imps.hpp \
+ tree_policy/node_metadata_selector.hpp \
+ tree_policy/null_node_update_imp.hpp \
+ tree_policy/order_statistics_imp.hpp \
+ tree_policy/sample_tree_node_update.hpp \
+ tree_trace_base.hpp \
+ trie_policy/node_metadata_selector.hpp \
+ trie_policy/null_node_update_imp.hpp \
+ trie_policy/order_statistics_imp.hpp \
+ trie_policy/prefix_search_node_update_imp.hpp \
+ trie_policy/sample_trie_e_access_traits.hpp \
+ trie_policy/sample_trie_node_update.hpp \
+ trie_policy/string_trie_e_access_traits_imp.hpp \
+ trie_policy/trie_policy_base.hpp \
+ types_traits.hpp \
+ type_utils.hpp \
+ unordered_iterator/const_iterator.hpp \
+ unordered_iterator/const_point_iterator.hpp \
+ unordered_iterator/iterator.hpp \
+ unordered_iterator/point_iterator.hpp
+
+PBHDRSDIRS= \
+ pairing_heap_ \
+ splay_tree_ \
+ list_update_map_ \
+ basic_tree_policy \
+ trie_policy \
+ gp_hash_table_map_ \
+ tree_policy \
+ binomial_heap_base_ \
+ resize_policy \
+ bin_search_tree_ \
+ binomial_heap_ \
+ thin_heap_ \
+ pat_trie_ \
+ cc_hash_table_map_ \
+ rc_binomial_heap_ \
+ left_child_next_sibling_heap_ \
+ unordered_iterator \
+ binary_heap_ \
+ ov_tree_map_ \
+ hash_fn \
+ eq_fn \
+ rb_tree_map_ \
+ list_update_policy
+
+.for D in ${PBHDRSDIRS}
+PHDRGRP$D:= ${PBHDRS:M$D/*:S;^;${SRCDIR}/include/ext/pb_ds/detail/;}
+PHDRGRP$DDIR= ${CXXINCLUDEDIR}/ext/pb_ds/detail/$D
+INCSGROUPS+= PHDRGRP$D
+.endfor
+
+TARGETHDRS= abi/compatibility.h \
+ allocator/new_allocator_base.h \
+ io/basic_file_stdio.h \
+ io/c_io_stdio.h \
+ locale/generic/c_locale.h \
+ locale/generic/c++locale_internal.h \
+ locale/generic/messages_members.h \
+ locale/generic/time_members.h \
+ os/bsd/freebsd/ctype_base.h \
+ os/bsd/freebsd/ctype_inline.h \
+ os/bsd/freebsd/ctype_noninline.h \
+ os/bsd/freebsd/os_defines.h
+TARGETHDRS:= ${TARGETHDRS:S;^;${SRCDIR}/config/;}
+TARGETHDRS+= c++config.h
+TARGETHDRSNAME_basic_file_stdio.h= basic_file.h
+TARGETHDRSNAME_c_io_stdio.h= c++io.h
+TARGETHDRSNAME_c_locale.h= c++locale.h
+TARGETHDRSNAME_new_allocator_base.h= c++allocator.h
+TARGETHDRSDIR= ${CXXINCLUDEDIR}/bits
+
+MARCHHDRS= atomic_word.h cpu_defines.h cxxabi_tweaks.h
+.for h in ${MARCHHDRS}
+.if exists(${SRCDIR}/config/cpu/${MARCHDIR}/${h})
+TARGETHDRS+= ${SRCDIR}/config/cpu/${MARCHDIR}/${h}
+.else
+TARGETHDRS+= ${SRCDIR}/config/cpu/generic/${h}
+.endif
+.endfor
+
+THRHDRS= gthr.h gthr-single.h gthr-posix.h gthr-tpf.h gthr-default.h
+THRHDRSDIR= ${CXXINCLUDEDIR}/bits
+uppercase = [ABCDEFGHIJKLMNOPQRSTUVWXYZ_]
+
+gthr.h: ${GCCDIR}/gthr.h
+ sed -e '/^#pragma/b' \
+ -e '/^#/s/\(${uppercase}${uppercase}*\)/_GLIBCXX_\1/g' \
+ -e 's/_GLIBCXX_SUPPORTS_WEAK/__GXX_WEAK__/g' \
+ -e 's,^#include "\(.*\)",#include <bits/\1>,g' \
+ < ${.ALLSRC} > ${.TARGET}
+
+gthr-single.h: ${GCCDIR}/gthr-single.h
+ sed -e 's/\(UNUSED\)/_GLIBCXX_\1/g' \
+ -e 's/\(GCC${uppercase}*_H\)/_GLIBCXX_\1/g' \
+ < ${.ALLSRC} > ${.TARGET}
+
+gthr-posix.h: ${GCCDIR}/gthr-posix.h
+ sed -e 's/\(UNUSED\)/_GLIBCXX_\1/g' \
+ -e 's/\(GCC${uppercase}*_H\)/_GLIBCXX_\1/g' \
+ -e 's/SUPPORTS_WEAK/__GXX_WEAK__/g' \
+ -e 's/\(${uppercase}*USE_WEAK\)/_GLIBCXX_\1/g' \
+ < ${.ALLSRC} > ${.TARGET}
+
+gthr-tpf.h: ${GCCDIR}/gthr-posix.h
+ sed -e 's/\(UNUSED\)/_GLIBCXX_\1/g' \
+ -e 's/\(GCC${uppercase}*_H\)/_GLIBCXX_\1/g' \
+ -e 's/SUPPORTS_WEAK/__GXX_WEAK__/g' \
+ -e 's/\(${uppercase}*USE_WEAK\)/_GLIBCXX_\1/g' \
+ < ${.ALLSRC} > ${.TARGET}
+
+gthr-default.h: ${GCCDIR}/gthr-posix.h
+ sed -e 's/\(UNUSED\)/_GLIBCXX_\1/g' \
+ -e 's/\(GCC${uppercase}*_H\)/_GLIBCXX_\1/g' \
+ -e 's/SUPPORTS_WEAK/__GXX_WEAK__/g' \
+ -e 's/\(${uppercase}*USE_WEAK\)/_GLIBCXX_\1/g' \
+ -e 's,^#include "\(.*\)",#include <bits/\1>,g' \
+ < ${.ALLSRC} > ${.TARGET}
+
+CLEANFILES+= ${THRHDRS}
+
+unwind.h: ${GCCDIR}/unwind-generic.h
+ ln -sf ${.ALLSRC} ${.TARGET}
+
+SRCS+= unwind.h
+CLEANFILES+= unwind.h
+
+DATESTAMP!= cat ${GCCDIR}/DATESTAMP
+
+c++config.h: ${.CURDIR}/config.h ${SRCDIR}/include/bits/c++config
+ sed -e "s/\\(define __GLIBCXX__\\)/\1 ${DATESTAMP}/" \
+ -e 's/\(define _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY\)/\1 1/' \
+ -e 's/\(define _GLIBCXX_NAMESPACE_ASSOCIATION_VERSION\)/\1 0/' \
+ < ${SRCDIR}/include/bits/c++config > ${.TARGET} && \
+ sed -e 's/HAVE_/_GLIBCXX_HAVE_/g' \
+ -e 's/PACKAGE/_GLIBCXX_PACKAGE/g' \
+ -e 's/VERSION/_GLIBCXX_VERSION/g' \
+ -e 's/WORDS_/_GLIBCXX_WORDS_/g' \
+ < ${.CURDIR}/config.h >> ${.TARGET} && \
+ echo "#endif // _CXXCONFIG_" >> ${.TARGET}
+CLEANFILES+= c++config.h
+
+# Symbol versioning.
+
+VERSION_MAP= libstdc++.map
+
+${VERSION_MAP}: ${SRCDIR}/config/abi/pre/gnu.ver
+ ln -sf ${.ALLSRC} ${.TARGET}
+
+CLEANFILES+= ${VERSION_MAP}
+
+.include <bsd.lib.mk>
diff --git a/gnu/lib/libstdc++/config.h b/gnu/lib/libstdc++/config.h
new file mode 100644
index 0000000..4109752
--- /dev/null
+++ b/gnu/lib/libstdc++/config.h
@@ -0,0 +1,1103 @@
+/* $FreeBSD$ */
+#ifndef __ISO_C_VISIBLE
+#include <sys/cdefs.h>
+#endif
+
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the `acosf' function. */
+#define HAVE_ACOSF 1
+
+/* Define to 1 if you have the `acosl' function. */
+/* #undef HAVE_ACOSL */
+
+/* Define to 1 if you have the `asinf' function. */
+#define HAVE_ASINF 1
+
+/* Define to 1 if you have the `asinl' function. */
+/* #undef HAVE_ASINL */
+
+/* Define to 1 if you have the `atan2f' function. */
+#define HAVE_ATAN2F 1
+
+/* Define to 1 if you have the `atan2l' function. */
+/* #undef HAVE_ATAN2L */
+
+/* Define to 1 if you have the `atanf' function. */
+#define HAVE_ATANF 1
+
+/* Define to 1 if you have the `atanl' function. */
+/* #undef HAVE_ATANL */
+
+/* Define to 1 if you have the `ceilf' function. */
+#define HAVE_CEILF 1
+
+/* Define to 1 if you have the `ceill' function. */
+#define HAVE_CEILL 1
+
+/* Define to 1 if you have the <complex.h> header file. */
+#define HAVE_COMPLEX_H 1
+
+/* Define to 1 if you have the `copysign' function. */
+#define HAVE_COPYSIGN 1
+
+/* Define to 1 if you have the `copysignf' function. */
+#define HAVE_COPYSIGNF 1
+
+/* Define to 1 if you have the `copysignl' function. */
+#define HAVE_COPYSIGNL 1
+
+/* Define to 1 if you have the `cosf' function. */
+#define HAVE_COSF 1
+
+/* Define to 1 if you have the `coshf' function. */
+#define HAVE_COSHF 1
+
+/* Define to 1 if you have the `coshl' function. */
+/* #undef HAVE_COSHL */
+
+/* Define to 1 if you have the `cosl' function. */
+/* #undef HAVE_COSL */
+
+/* Define to 1 if you have the <endian.h> header file. */
+/* #undef HAVE_ENDIAN_H */
+
+/* Define to 1 if you have the `expf' function. */
+#define HAVE_EXPF 1
+
+/* Define to 1 if you have the `expl' function. */
+/* #undef HAVE_EXPL */
+
+/* Define to 1 if you have the `fabsf' function. */
+#define HAVE_FABSF 1
+
+/* Define to 1 if you have the `fabsl' function. */
+#define HAVE_FABSL 1
+
+/* Define to 1 if you have the <fenv.h> header file. */
+#define HAVE_FENV_H 1
+
+/* Define to 1 if you have the `finite' function. */
+#define HAVE_FINITE 1
+
+/* Define to 1 if you have the `finitef' function. */
+#define HAVE_FINITEF 1
+
+/* Define to 1 if you have the `finitel' function. */
+/* #undef HAVE_FINITEL */
+
+/* Define to 1 if you have the <float.h> header file. */
+#define HAVE_FLOAT_H 1
+
+/* Define to 1 if you have the `floorf' function. */
+#define HAVE_FLOORF 1
+
+/* Define to 1 if you have the `floorl' function. */
+#define HAVE_FLOORL 1
+
+/* Define to 1 if you have the `fmodf' function. */
+#define HAVE_FMODF 1
+
+/* Define to 1 if you have the `fmodl' function. */
+/* #undef HAVE_FMODL */
+
+/* Define to 1 if you have the `fpclass' function. */
+/* #undef HAVE_FPCLASS */
+
+/* Define to 1 if you have the <fp.h> header file. */
+/* #undef HAVE_FP_H */
+
+/* Define to 1 if you have the `frexpf' function. */
+#define HAVE_FREXPF 1
+
+/* Define to 1 if you have the `frexpl' function. */
+#define HAVE_FREXPL 1
+
+/* Define to 1 if you have the <gconv.h> header file. */
+/* #undef HAVE_GCONV_H */
+
+/* Define if _Unwind_GetIPInfo is available. */
+#define HAVE_GETIPINFO 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define if gthr-default.h exists (meaning that threading support is
+ enabled). */
+#define HAVE_GTHR_DEFAULT 1
+
+/* Define to 1 if you have the `hypot' function. */
+#define HAVE_HYPOT 1
+
+/* Define to 1 if you have the `hypotf' function. */
+#define HAVE_HYPOTF 1
+
+/* Define to 1 if you have the `hypotl' function. */
+/* #undef HAVE_HYPOTL */
+
+/* Define to 1 if you have the `iconv' function. */
+/* #undef HAVE_ICONV */
+
+/* Define to 1 if you have the `iconv_close' function. */
+/* #undef HAVE_ICONV_CLOSE */
+
+/* Define to 1 if you have the `iconv_open' function. */
+/* #undef HAVE_ICONV_OPEN */
+
+/* Define to 1 if you have the <ieeefp.h> header file. */
+#define HAVE_IEEEFP_H 1
+
+/* Define if int64_t is available in <stdint.h>. */
+#define HAVE_INT64_T 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `isinf' function. */
+#define HAVE_ISINF 1
+
+/* Define to 1 if you have the `isinff' function. */
+/* #undef HAVE_ISINFF */
+
+/* Define to 1 if you have the `isinfl' function. */
+/* #undef HAVE_ISINFL */
+
+/* Define to 1 if you have the `isnan' function. */
+#define HAVE_ISNAN 1
+
+/* Define to 1 if you have the `isnanf' function. */
+#define HAVE_ISNANF 1
+
+/* Define to 1 if you have the `isnanl' function. */
+/* #undef HAVE_ISNANL */
+
+/* Defined if iswblank exists. */
+#define HAVE_ISWBLANK 1
+
+/* Define if LC_MESSAGES is available in <locale.h>. */
+#define HAVE_LC_MESSAGES 1
+
+/* Define to 1 if you have the `ldexpf' function. */
+#define HAVE_LDEXPF 1
+
+/* Define to 1 if you have the `ldexpl' function. */
+#define HAVE_LDEXPL 1
+
+/* Define to 1 if you have the <libintl.h> header file. */
+/* #undef HAVE_LIBINTL_H */
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Only used in build directory testsuite_hooks.h. */
+#define HAVE_LIMIT_AS 1
+
+/* Only used in build directory testsuite_hooks.h. */
+#define HAVE_LIMIT_DATA 1
+
+/* Only used in build directory testsuite_hooks.h. */
+#define HAVE_LIMIT_FSIZE 1
+
+/* Only used in build directory testsuite_hooks.h. */
+#define HAVE_LIMIT_RSS 1
+
+/* Only used in build directory testsuite_hooks.h. */
+#define HAVE_LIMIT_VMEM 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have the `log10f' function. */
+#define HAVE_LOG10F 1
+
+/* Define to 1 if you have the `log10l' function. */
+/* #undef HAVE_LOG10L */
+
+/* Define to 1 if you have the `logf' function. */
+#define HAVE_LOGF 1
+
+/* Define to 1 if you have the `logl' function. */
+/* #undef HAVE_LOGL */
+
+/* Define to 1 if you have the <machine/endian.h> header file. */
+#define HAVE_MACHINE_ENDIAN_H 1
+
+/* Define to 1 if you have the <machine/param.h> header file. */
+#define HAVE_MACHINE_PARAM_H 1
+
+/* Define if mbstate_t exists in wchar.h. */
+#define HAVE_MBSTATE_T 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the `modf' function. */
+#define HAVE_MODF 1
+
+/* Define to 1 if you have the `modff' function. */
+#define HAVE_MODFF 1
+
+/* Define to 1 if you have the `modfl' function. */
+#define HAVE_MODFL 1
+
+/* Define to 1 if you have the <nan.h> header file. */
+/* #undef HAVE_NAN_H */
+
+/* Define to 1 if you have the `nl_langinfo' function. */
+#define HAVE_NL_LANGINFO 1
+
+/* Define if poll is available in <poll.h>. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the `powf' function. */
+#define HAVE_POWF 1
+
+/* Define to 1 if you have the `powl' function. */
+/* #undef HAVE_POWL */
+
+/* Define to 1 if you have the `qfpclass' function. */
+/* #undef HAVE_QFPCLASS */
+
+/* Define to 1 if you have the `setenv' function. */
+#define HAVE_SETENV 1
+
+/* Define if sigsetjmp is available. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if you have the `sincos' function. */
+/* #undef HAVE_SINCOS */
+
+/* Define to 1 if you have the `sincosf' function. */
+/* #undef HAVE_SINCOSF */
+
+/* Define to 1 if you have the `sincosl' function. */
+/* #undef HAVE_SINCOSL */
+
+/* Define to 1 if you have the `sinf' function. */
+#define HAVE_SINF 1
+
+/* Define to 1 if you have the `sinhf' function. */
+#define HAVE_SINHF 1
+
+/* Define to 1 if you have the `sinhl' function. */
+/* #undef HAVE_SINHL */
+
+/* Define to 1 if you have the `sinl' function. */
+/* #undef HAVE_SINL */
+
+/* Define to 1 if you have the `sqrtf' function. */
+#define HAVE_SQRTF 1
+
+/* Define to 1 if you have the `sqrtl' function. */
+/* #undef HAVE_SQRTL */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strtof' function. */
+#define HAVE_STRTOF 1
+
+/* Define to 1 if you have the `strtold' function. */
+#define HAVE_STRTOLD 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+#define HAVE_SYS_IPC_H 1
+
+/* Define to 1 if you have the <sys/isa_defs.h> header file. */
+/* #undef HAVE_SYS_ISA_DEFS_H */
+
+/* Define to 1 if you have the <sys/machine.h> header file. */
+/* #undef HAVE_SYS_MACHINE_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+/* #undef HAVE_SYS_PARAM_H */
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/sem.h> header file. */
+#define HAVE_SYS_SEM_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define if S_IFREG is available in <sys/stat.h>. */
+/* #undef HAVE_S_IFREG */
+
+/* Define if S_IFREG is available in <sys/stat.h>. */
+#define HAVE_S_ISREG 1
+
+/* Define to 1 if you have the `tanf' function. */
+#define HAVE_TANF 1
+
+/* Define to 1 if you have the `tanhf' function. */
+#define HAVE_TANHF 1
+
+/* Define to 1 if you have the `tanhl' function. */
+/* #undef HAVE_TANHL */
+
+/* Define to 1 if you have the `tanl' function. */
+/* #undef HAVE_TANL */
+
+/* Define to 1 if the target supports thread-local storage. */
+#if !defined(__arm__) && !defined(__mips__)
+#define HAVE_TLS 1
+#endif
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+#if __ISO_C_VISIBLE >= 1999
+/* Defined if vfwscanf exists. */
+#define HAVE_VFWSCANF 1
+
+/* Defined if vswscanf exists. */
+#define HAVE_VSWSCANF 1
+
+/* Defined if vwscanf exists. */
+#define HAVE_VWSCANF 1
+#endif /* __ISO_C_VISIBLE >= 1999 */
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+#if __ISO_C_VISIBLE >= 1999
+/* Defined if wcstof exists. */
+#define HAVE_WCSTOF 1
+#endif /* __ISO_C_VISIBLE >= 1999 */
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define if writev is available in <sys/uio.h>. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the `_acosf' function. */
+/* #undef HAVE__ACOSF */
+
+/* Define to 1 if you have the `_acosl' function. */
+/* #undef HAVE__ACOSL */
+
+/* Define to 1 if you have the `_asinf' function. */
+/* #undef HAVE__ASINF */
+
+/* Define to 1 if you have the `_asinl' function. */
+/* #undef HAVE__ASINL */
+
+/* Define to 1 if you have the `_atan2f' function. */
+/* #undef HAVE__ATAN2F */
+
+/* Define to 1 if you have the `_atan2l' function. */
+/* #undef HAVE__ATAN2L */
+
+/* Define to 1 if you have the `_atanf' function. */
+/* #undef HAVE__ATANF */
+
+/* Define to 1 if you have the `_atanl' function. */
+/* #undef HAVE__ATANL */
+
+/* Define to 1 if you have the `_ceilf' function. */
+/* #undef HAVE__CEILF */
+
+/* Define to 1 if you have the `_ceill' function. */
+/* #undef HAVE__CEILL */
+
+/* Define to 1 if you have the `_copysign' function. */
+/* #undef HAVE__COPYSIGN */
+
+/* Define to 1 if you have the `_copysignl' function. */
+/* #undef HAVE__COPYSIGNL */
+
+/* Define to 1 if you have the `_cosf' function. */
+/* #undef HAVE__COSF */
+
+/* Define to 1 if you have the `_coshf' function. */
+/* #undef HAVE__COSHF */
+
+/* Define to 1 if you have the `_coshl' function. */
+/* #undef HAVE__COSHL */
+
+/* Define to 1 if you have the `_cosl' function. */
+/* #undef HAVE__COSL */
+
+/* Define to 1 if you have the `_expf' function. */
+/* #undef HAVE__EXPF */
+
+/* Define to 1 if you have the `_expl' function. */
+/* #undef HAVE__EXPL */
+
+/* Define to 1 if you have the `_fabsf' function. */
+/* #undef HAVE__FABSF */
+
+/* Define to 1 if you have the `_fabsl' function. */
+/* #undef HAVE__FABSL */
+
+/* Define to 1 if you have the `_finite' function. */
+/* #undef HAVE__FINITE */
+
+/* Define to 1 if you have the `_finitef' function. */
+/* #undef HAVE__FINITEF */
+
+/* Define to 1 if you have the `_finitel' function. */
+/* #undef HAVE__FINITEL */
+
+/* Define to 1 if you have the `_floorf' function. */
+/* #undef HAVE__FLOORF */
+
+/* Define to 1 if you have the `_floorl' function. */
+/* #undef HAVE__FLOORL */
+
+/* Define to 1 if you have the `_fmodf' function. */
+/* #undef HAVE__FMODF */
+
+/* Define to 1 if you have the `_fmodl' function. */
+/* #undef HAVE__FMODL */
+
+/* Define to 1 if you have the `_fpclass' function. */
+/* #undef HAVE__FPCLASS */
+
+/* Define to 1 if you have the `_frexpf' function. */
+/* #undef HAVE__FREXPF */
+
+/* Define to 1 if you have the `_frexpl' function. */
+/* #undef HAVE__FREXPL */
+
+/* Define to 1 if you have the `_hypot' function. */
+/* #undef HAVE__HYPOT */
+
+/* Define to 1 if you have the `_hypotf' function. */
+/* #undef HAVE__HYPOTF */
+
+/* Define to 1 if you have the `_hypotl' function. */
+/* #undef HAVE__HYPOTL */
+
+/* Define to 1 if you have the `_isinf' function. */
+/* #undef HAVE__ISINF */
+
+/* Define to 1 if you have the `_isinff' function. */
+/* #undef HAVE__ISINFF */
+
+/* Define to 1 if you have the `_isinfl' function. */
+/* #undef HAVE__ISINFL */
+
+/* Define to 1 if you have the `_isnan' function. */
+/* #undef HAVE__ISNAN */
+
+/* Define to 1 if you have the `_isnanf' function. */
+/* #undef HAVE__ISNANF */
+
+/* Define to 1 if you have the `_isnanl' function. */
+/* #undef HAVE__ISNANL */
+
+/* Define to 1 if you have the `_ldexpf' function. */
+/* #undef HAVE__LDEXPF */
+
+/* Define to 1 if you have the `_ldexpl' function. */
+/* #undef HAVE__LDEXPL */
+
+/* Define to 1 if you have the `_log10f' function. */
+/* #undef HAVE__LOG10F */
+
+/* Define to 1 if you have the `_log10l' function. */
+/* #undef HAVE__LOG10L */
+
+/* Define to 1 if you have the `_logf' function. */
+/* #undef HAVE__LOGF */
+
+/* Define to 1 if you have the `_logl' function. */
+/* #undef HAVE__LOGL */
+
+/* Define to 1 if you have the `_modf' function. */
+/* #undef HAVE__MODF */
+
+/* Define to 1 if you have the `_modff' function. */
+/* #undef HAVE__MODFF */
+
+/* Define to 1 if you have the `_modfl' function. */
+/* #undef HAVE__MODFL */
+
+/* Define to 1 if you have the `_powf' function. */
+/* #undef HAVE__POWF */
+
+/* Define to 1 if you have the `_powl' function. */
+/* #undef HAVE__POWL */
+
+/* Define to 1 if you have the `_qfpclass' function. */
+/* #undef HAVE__QFPCLASS */
+
+/* Define to 1 if you have the `_sincos' function. */
+/* #undef HAVE__SINCOS */
+
+/* Define to 1 if you have the `_sincosf' function. */
+/* #undef HAVE__SINCOSF */
+
+/* Define to 1 if you have the `_sincosl' function. */
+/* #undef HAVE__SINCOSL */
+
+/* Define to 1 if you have the `_sinf' function. */
+/* #undef HAVE__SINF */
+
+/* Define to 1 if you have the `_sinhf' function. */
+/* #undef HAVE__SINHF */
+
+/* Define to 1 if you have the `_sinhl' function. */
+/* #undef HAVE__SINHL */
+
+/* Define to 1 if you have the `_sinl' function. */
+/* #undef HAVE__SINL */
+
+/* Define to 1 if you have the `_sqrtf' function. */
+/* #undef HAVE__SQRTF */
+
+/* Define to 1 if you have the `_sqrtl' function. */
+/* #undef HAVE__SQRTL */
+
+/* Define to 1 if you have the `_tanf' function. */
+/* #undef HAVE__TANF */
+
+/* Define to 1 if you have the `_tanhf' function. */
+/* #undef HAVE__TANHF */
+
+/* Define to 1 if you have the `_tanhl' function. */
+/* #undef HAVE__TANHL */
+
+/* Define to 1 if you have the `_tanl' function. */
+/* #undef HAVE__TANL */
+
+/* Define if the compiler/host combination has __builtin_abs. */
+#define HAVE___BUILTIN_ABS 1
+
+/* Define if the compiler/host combination has __builtin_cos. */
+#define HAVE___BUILTIN_COS 1
+
+/* Define if the compiler/host combination has __builtin_cosf. */
+#define HAVE___BUILTIN_COSF 1
+
+/* Define if the compiler/host combination has __builtin_cosl. */
+#define HAVE___BUILTIN_COSL 1
+
+/* Define if the compiler/host combination has __builtin_fabs. */
+#define HAVE___BUILTIN_FABS 1
+
+/* Define if the compiler/host combination has __builtin_fabsf. */
+#define HAVE___BUILTIN_FABSF 1
+
+/* Define if the compiler/host combination has __builtin_fabsl. */
+#define HAVE___BUILTIN_FABSL 1
+
+/* Define if the compiler/host combination has __builtin_labs. */
+#define HAVE___BUILTIN_LABS 1
+
+/* Define if the compiler/host combination has __builtin_sin. */
+#define HAVE___BUILTIN_SIN 1
+
+/* Define if the compiler/host combination has __builtin_sinf. */
+#define HAVE___BUILTIN_SINF 1
+
+/* Define if the compiler/host combination has __builtin_sinl. */
+#define HAVE___BUILTIN_SINL 1
+
+/* Define if the compiler/host combination has __builtin_sqrt. */
+#define HAVE___BUILTIN_SQRT 1
+
+/* Define if the compiler/host combination has __builtin_sqrtf. */
+#define HAVE___BUILTIN_SQRTF 1
+
+/* Define if the compiler/host combination has __builtin_sqrtl. */
+#define HAVE___BUILTIN_SQRTL 1
+
+/* Define to 1 if you have the `__signbit' function. */
+#define HAVE___SIGNBIT 1
+
+/* Define to 1 if you have the `__signbitf' function. */
+#define HAVE___SIGNBITF 1
+
+/* Define to 1 if you have the `__signbitl' function. */
+#define HAVE___SIGNBITL 1
+
+/* Name of package */
+/* #undef PACKAGE */
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "package-unused"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "package-unused version-unused"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libstdc++"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "version-unused"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+/* #undef VERSION */
+
+/* Define if builtin atomic operations are supported on this host. */
+#if defined(__amd64__) || defined(__i386__)
+#define _GLIBCXX_ATOMIC_BUILTINS 1
+#endif
+
+/* Define to use concept checking code from the boost libraries. */
+/* #undef _GLIBCXX_CONCEPT_CHECKS */
+
+/* Define if a fully dynamic basic_string is wanted. */
+/* #undef _GLIBCXX_FULLY_DYNAMIC_STRING */
+
+/* Define to 1 if a full hosted library is built, or 0 if freestanding. */
+#define _GLIBCXX_HOSTED 1
+
+/* Define if compatibility should be provided for -mlong-double-64. */
+/* #undef _GLIBCXX_LONG_DOUBLE_COMPAT */
+
+/* Define if ptrdiff_t is int. */
+#if !defined(__LP64__)
+#define _GLIBCXX_PTRDIFF_T_IS_INT 1
+#endif
+
+/* Define if using setrlimit to set resource limits during "make check" */
+#define _GLIBCXX_RES_LIMITS 1
+
+/* Define if size_t is unsigned int. */
+#if !defined(__LP64__)
+#define _GLIBCXX_SIZE_T_IS_UINT 1
+#endif
+
+/* Define if the compiler is configured for setjmp/longjmp exceptions. */
+/* #undef _GLIBCXX_SJLJ_EXCEPTIONS */
+
+/* Define to use symbol versioning in the shared library. */
+#define _GLIBCXX_SYMVER 1
+
+/* Define to use darwin versioning in the shared library. */
+/* #undef _GLIBCXX_SYMVER_DARWIN */
+
+/* Define to use GNU versioning in the shared library. */
+#define _GLIBCXX_SYMVER_GNU 1
+
+/* Define to use GNU namespace versioning in the shared library. */
+/* #undef _GLIBCXX_SYMVER_GNU_NAMESPACE */
+
+/* Define if C99 functions or macros from <wchar.h>, <math.h>, <complex.h>,
+ <stdio.h>, and <stdlib.h> can be used or exposed. */
+/* #undef _GLIBCXX_USE_C99 */
+
+/* Define if C99 functions in <complex.h> should be used in <complex>. Using
+ compiler builtins for these functions requires corresponding C99 library
+ functions to be present. */
+/* #undef _GLIBCXX_USE_C99_COMPLEX */
+
+/* Define if C99 functions in <complex.h> should be used in <tr1/complex>.
+ Using compiler builtins for these functions requires corresponding C99
+ library functions to be present. */
+/* #undef _GLIBCXX_USE_C99_COMPLEX_TR1 */
+
+/* Define if C99 functions in <ctype.h> should be imported in <tr1/cctype> in
+ namespace std::tr1. */
+#define _GLIBCXX_USE_C99_CTYPE_TR1 1
+
+/* Define if C99 functions in <fenv.h> should be imported in <tr1/cfenv> in
+ namespace std::tr1. */
+#define _GLIBCXX_USE_C99_FENV_TR1 1
+
+/* Define if C99 functions in <inttypes.h> should be imported in
+ <tr1/cinttypes> in namespace std::tr1. */
+#define _GLIBCXX_USE_C99_INTTYPES_TR1 1
+
+/* Define if C99 functions or macros in <math.h> should be imported in <cmath>
+ in namespace std. */
+#define _GLIBCXX_USE_C99_MATH 1
+
+/* Define if C99 functions or macros in <math.h> should be imported in
+ <tr1/cmath> in namespace std::tr1. */
+/* #undef _GLIBCXX_USE_C99_MATH_TR1 */
+
+/* Define if C99 types in <stdint.h> should be imported in <tr1/cstdint> in
+ namespace std::tr1. */
+#define _GLIBCXX_USE_C99_STDINT_TR1 1
+
+/* Define if iconv and related functions exist and are usable. */
+#define _GLIBCXX_USE_ICONV 1
+
+/* Define if LFS support is available. */
+/* #undef _GLIBCXX_USE_LFS */
+
+/* Define if code specialized for long long should be used. */
+#define _GLIBCXX_USE_LONG_LONG 1
+
+/* Define if NLS translations are to be used. */
+/* #undef _GLIBCXX_USE_NLS */
+
+/* Define if dev/random and dev/urandom are available for the random_device of
+ TR1 (Chapter 5.1). */
+#define _GLIBCXX_USE_RANDOM_TR1 1
+
+/* Define if code specialized for wchar_t should be used. */
+#define _GLIBCXX_USE_WCHAR_T 1
+
+#if defined (HAVE__ACOSF) && ! defined (HAVE_ACOSF)
+# define HAVE_ACOSF 1
+# define acosf _acosf
+#endif
+
+#if defined (HAVE__ACOSL) && ! defined (HAVE_ACOSL)
+# define HAVE_ACOSL 1
+# define acosl _acosl
+#endif
+
+#if defined (HAVE__ASINF) && ! defined (HAVE_ASINF)
+# define HAVE_ASINF 1
+# define asinf _asinf
+#endif
+
+#if defined (HAVE__ASINL) && ! defined (HAVE_ASINL)
+# define HAVE_ASINL 1
+# define asinl _asinl
+#endif
+
+#if defined (HAVE__ATAN2F) && ! defined (HAVE_ATAN2F)
+# define HAVE_ATAN2F 1
+# define atan2f _atan2f
+#endif
+
+#if defined (HAVE__ATAN2L) && ! defined (HAVE_ATAN2L)
+# define HAVE_ATAN2L 1
+# define atan2l _atan2l
+#endif
+
+#if defined (HAVE__ATANF) && ! defined (HAVE_ATANF)
+# define HAVE_ATANF 1
+# define atanf _atanf
+#endif
+
+#if defined (HAVE__ATANL) && ! defined (HAVE_ATANL)
+# define HAVE_ATANL 1
+# define atanl _atanl
+#endif
+
+#if defined (HAVE__CEILF) && ! defined (HAVE_CEILF)
+# define HAVE_CEILF 1
+# define ceilf _ceilf
+#endif
+
+#if defined (HAVE__CEILL) && ! defined (HAVE_CEILL)
+# define HAVE_CEILL 1
+# define ceill _ceill
+#endif
+
+#if defined (HAVE__COPYSIGN) && ! defined (HAVE_COPYSIGN)
+# define HAVE_COPYSIGN 1
+# define copysign _copysign
+#endif
+
+#if defined (HAVE__COPYSIGNL) && ! defined (HAVE_COPYSIGNL)
+# define HAVE_COPYSIGNL 1
+# define copysignl _copysignl
+#endif
+
+#if defined (HAVE__COSF) && ! defined (HAVE_COSF)
+# define HAVE_COSF 1
+# define cosf _cosf
+#endif
+
+#if defined (HAVE__COSHF) && ! defined (HAVE_COSHF)
+# define HAVE_COSHF 1
+# define coshf _coshf
+#endif
+
+#if defined (HAVE__COSHL) && ! defined (HAVE_COSHL)
+# define HAVE_COSHL 1
+# define coshl _coshl
+#endif
+
+#if defined (HAVE__COSL) && ! defined (HAVE_COSL)
+# define HAVE_COSL 1
+# define cosl _cosl
+#endif
+
+#if defined (HAVE__EXPF) && ! defined (HAVE_EXPF)
+# define HAVE_EXPF 1
+# define expf _expf
+#endif
+
+#if defined (HAVE__EXPL) && ! defined (HAVE_EXPL)
+# define HAVE_EXPL 1
+# define expl _expl
+#endif
+
+#if defined (HAVE__FABSF) && ! defined (HAVE_FABSF)
+# define HAVE_FABSF 1
+# define fabsf _fabsf
+#endif
+
+#if defined (HAVE__FABSL) && ! defined (HAVE_FABSL)
+# define HAVE_FABSL 1
+# define fabsl _fabsl
+#endif
+
+#if defined (HAVE__FINITE) && ! defined (HAVE_FINITE)
+# define HAVE_FINITE 1
+# define finite _finite
+#endif
+
+#if defined (HAVE__FINITEF) && ! defined (HAVE_FINITEF)
+# define HAVE_FINITEF 1
+# define finitef _finitef
+#endif
+
+#if defined (HAVE__FINITEL) && ! defined (HAVE_FINITEL)
+# define HAVE_FINITEL 1
+# define finitel _finitel
+#endif
+
+#if defined (HAVE__FLOORF) && ! defined (HAVE_FLOORF)
+# define HAVE_FLOORF 1
+# define floorf _floorf
+#endif
+
+#if defined (HAVE__FLOORL) && ! defined (HAVE_FLOORL)
+# define HAVE_FLOORL 1
+# define floorl _floorl
+#endif
+
+#if defined (HAVE__FMODF) && ! defined (HAVE_FMODF)
+# define HAVE_FMODF 1
+# define fmodf _fmodf
+#endif
+
+#if defined (HAVE__FMODL) && ! defined (HAVE_FMODL)
+# define HAVE_FMODL 1
+# define fmodl _fmodl
+#endif
+
+#if defined (HAVE__FPCLASS) && ! defined (HAVE_FPCLASS)
+# define HAVE_FPCLASS 1
+# define fpclass _fpclass
+#endif
+
+#if defined (HAVE__FREXPF) && ! defined (HAVE_FREXPF)
+# define HAVE_FREXPF 1
+# define frexpf _frexpf
+#endif
+
+#if defined (HAVE__FREXPL) && ! defined (HAVE_FREXPL)
+# define HAVE_FREXPL 1
+# define frexpl _frexpl
+#endif
+
+#if defined (HAVE__HYPOT) && ! defined (HAVE_HYPOT)
+# define HAVE_HYPOT 1
+# define hypot _hypot
+#endif
+
+#if defined (HAVE__HYPOTF) && ! defined (HAVE_HYPOTF)
+# define HAVE_HYPOTF 1
+# define hypotf _hypotf
+#endif
+
+#if defined (HAVE__HYPOTL) && ! defined (HAVE_HYPOTL)
+# define HAVE_HYPOTL 1
+# define hypotl _hypotl
+#endif
+
+#if defined (HAVE__ISINF) && ! defined (HAVE_ISINF)
+# define HAVE_ISINF 1
+# define isinf _isinf
+#endif
+
+#if defined (HAVE__ISINFF) && ! defined (HAVE_ISINFF)
+# define HAVE_ISINFF 1
+# define isinff _isinff
+#endif
+
+#if defined (HAVE__ISINFL) && ! defined (HAVE_ISINFL)
+# define HAVE_ISINFL 1
+# define isinfl _isinfl
+#endif
+
+#if defined (HAVE__ISNAN) && ! defined (HAVE_ISNAN)
+# define HAVE_ISNAN 1
+# define isnan _isnan
+#endif
+
+#if defined (HAVE__ISNANF) && ! defined (HAVE_ISNANF)
+# define HAVE_ISNANF 1
+# define isnanf _isnanf
+#endif
+
+#if defined (HAVE__ISNANL) && ! defined (HAVE_ISNANL)
+# define HAVE_ISNANL 1
+# define isnanl _isnanl
+#endif
+
+#if defined (HAVE__LDEXPF) && ! defined (HAVE_LDEXPF)
+# define HAVE_LDEXPF 1
+# define ldexpf _ldexpf
+#endif
+
+#if defined (HAVE__LDEXPL) && ! defined (HAVE_LDEXPL)
+# define HAVE_LDEXPL 1
+# define ldexpl _ldexpl
+#endif
+
+#if defined (HAVE__LOG10F) && ! defined (HAVE_LOG10F)
+# define HAVE_LOG10F 1
+# define log10f _log10f
+#endif
+
+#if defined (HAVE__LOG10L) && ! defined (HAVE_LOG10L)
+# define HAVE_LOG10L 1
+# define log10l _log10l
+#endif
+
+#if defined (HAVE__LOGF) && ! defined (HAVE_LOGF)
+# define HAVE_LOGF 1
+# define logf _logf
+#endif
+
+#if defined (HAVE__LOGL) && ! defined (HAVE_LOGL)
+# define HAVE_LOGL 1
+# define logl _logl
+#endif
+
+#if defined (HAVE__MODF) && ! defined (HAVE_MODF)
+# define HAVE_MODF 1
+# define modf _modf
+#endif
+
+#if defined (HAVE__MODFF) && ! defined (HAVE_MODFF)
+# define HAVE_MODFF 1
+# define modff _modff
+#endif
+
+#if defined (HAVE__MODFL) && ! defined (HAVE_MODFL)
+# define HAVE_MODFL 1
+# define modfl _modfl
+#endif
+
+#if defined (HAVE__POWF) && ! defined (HAVE_POWF)
+# define HAVE_POWF 1
+# define powf _powf
+#endif
+
+#if defined (HAVE__POWL) && ! defined (HAVE_POWL)
+# define HAVE_POWL 1
+# define powl _powl
+#endif
+
+#if defined (HAVE__QFPCLASS) && ! defined (HAVE_QFPCLASS)
+# define HAVE_QFPCLASS 1
+# define qfpclass _qfpclass
+#endif
+
+#if defined (HAVE__SINCOS) && ! defined (HAVE_SINCOS)
+# define HAVE_SINCOS 1
+# define sincos _sincos
+#endif
+
+#if defined (HAVE__SINCOSF) && ! defined (HAVE_SINCOSF)
+# define HAVE_SINCOSF 1
+# define sincosf _sincosf
+#endif
+
+#if defined (HAVE__SINCOSL) && ! defined (HAVE_SINCOSL)
+# define HAVE_SINCOSL 1
+# define sincosl _sincosl
+#endif
+
+#if defined (HAVE__SINF) && ! defined (HAVE_SINF)
+# define HAVE_SINF 1
+# define sinf _sinf
+#endif
+
+#if defined (HAVE__SINHF) && ! defined (HAVE_SINHF)
+# define HAVE_SINHF 1
+# define sinhf _sinhf
+#endif
+
+#if defined (HAVE__SINHL) && ! defined (HAVE_SINHL)
+# define HAVE_SINHL 1
+# define sinhl _sinhl
+#endif
+
+#if defined (HAVE__SINL) && ! defined (HAVE_SINL)
+# define HAVE_SINL 1
+# define sinl _sinl
+#endif
+
+#if defined (HAVE__SQRTF) && ! defined (HAVE_SQRTF)
+# define HAVE_SQRTF 1
+# define sqrtf _sqrtf
+#endif
+
+#if defined (HAVE__SQRTL) && ! defined (HAVE_SQRTL)
+# define HAVE_SQRTL 1
+# define sqrtl _sqrtl
+#endif
+
+#if defined (HAVE__STRTOF) && ! defined (HAVE_STRTOF)
+# define HAVE_STRTOF 1
+# define strtof _strtof
+#endif
+
+#if defined (HAVE__STRTOLD) && ! defined (HAVE_STRTOLD)
+# define HAVE_STRTOLD 1
+# define strtold _strtold
+#endif
+
+#if defined (HAVE__TANF) && ! defined (HAVE_TANF)
+# define HAVE_TANF 1
+# define tanf _tanf
+#endif
+
+#if defined (HAVE__TANHF) && ! defined (HAVE_TANHF)
+# define HAVE_TANHF 1
+# define tanhf _tanhf
+#endif
+
+#if defined (HAVE__TANHL) && ! defined (HAVE_TANHL)
+# define HAVE_TANHL 1
+# define tanhl _tanhl
+#endif
+
+#if defined (HAVE__TANL) && ! defined (HAVE_TANL)
+# define HAVE_TANL 1
+# define tanl _tanl
+#endif
diff --git a/gnu/lib/libstdc++/doc/Makefile b/gnu/lib/libstdc++/doc/Makefile
new file mode 100644
index 0000000..b028519
--- /dev/null
+++ b/gnu/lib/libstdc++/doc/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+SRCDIR= ${.CURDIR}/../../../../contrib/libstdc++
+
+.PATH: ${SRCDIR}/../libio
+
+INFO = iostream
+
+INFOENTRY_iostream= "* iostream: (iostream). The GNU C++ I/O library."
+
+MAKEINFOFLAGS+= -I ${SRCDIR}/../libio
+
+.include <bsd.info.mk>
diff --git a/gnu/lib/libsupc++/Makefile b/gnu/lib/libsupc++/Makefile
new file mode 100644
index 0000000..f2fe8837
--- /dev/null
+++ b/gnu/lib/libsupc++/Makefile
@@ -0,0 +1,39 @@
+# $FreeBSD$
+
+GCCVER= 4.2
+GCCDIR= ${.CURDIR}/../../../contrib/gcc
+GCCLIB= ${.CURDIR}/../../../contrib/gcclibs
+SRCDIR= ${.CURDIR}/../../../contrib/libstdc++/libsupc++
+
+.PATH: ${SRCDIR} ${GCCLIB}/libiberty
+
+# Static only.
+LIB= supc++
+SRCS+= del_op.cc del_opnt.cc del_opv.cc del_opvnt.cc eh_alloc.cc eh_arm.cc \
+ eh_aux_runtime.cc eh_call.cc eh_catch.cc eh_exception.cc eh_globals.cc \
+ eh_personality.cc eh_term_handler.cc eh_terminate.cc eh_throw.cc \
+ eh_type.cc eh_unex_handler.cc guard.cc new_handler.cc new_op.cc \
+ new_opnt.cc new_opv.cc new_opvnt.cc pure.cc tinfo.cc tinfo2.cc \
+ vec.cc vterminate.cc
+
+# from libiberty:
+SRCS+= cp-demangle.c
+
+CFLAGS+= -DIN_GLIBCPP_V3 -DHAVE_CONFIG_H
+CFLAGS+= -I${GCCLIB}/include -I${SRCDIR} -I${GCCDIR}
+CFLAGS+= -I${.CURDIR}/../libstdc++ -I.
+CFLAGS+= -frandom-seed=RepeatabilityConsideredGood
+CXXFLAGS+= -fno-implicit-templates -ffunction-sections -fdata-sections
+PO_CXXFLAGS= ${CXXFLAGS:N-ffunction-sections}
+
+HDRS= exception new typeinfo cxxabi.h exception_defines.h
+INCS= ${HDRS:S;^;${SRCDIR}/;}
+INCSDIR=${INCLUDEDIR}/c++/${GCCVER}
+
+unwind.h: ${GCCDIR}/unwind-generic.h
+ ln -sf ${.ALLSRC} ${.TARGET}
+
+SRCS+= unwind.h
+CLEANFILES+= unwind.h
+
+.include <bsd.lib.mk>
OpenPOWER on IntegriCloud