From 1c07f937d7a3d56c9eec3a88cf9fd1bdad58b22a Mon Sep 17 00:00:00 2001 From: Oliver Rauch Date: Fri, 10 Nov 2000 06:47:25 +0000 Subject: [PATCH] *** empty log message *** --- Makefile.in | 59 + aclocal.m4 | 1062 +++++++++++++++++ config.guess | 883 ++++++++++++++ config.sub | 958 +++++++++++++++ doc/Makefile.in | 109 ++ doc/sane.png | Bin 0 -> 10753 bytes doc/sane.tex | 1869 ++++++++++++++++++++++++++++++ doc/xcam.man | 24 + doc/xscanimage.man | 135 +++ include/getopt.h | 129 +++ include/lalloca.h | 47 + include/sane/config.h.in | 342 ++++++ include/sane/sanei.h | 42 + include/sane/sanei_backend.h | 106 ++ include/sane/sanei_codec_ascii.h | 26 + include/sane/sanei_codec_bin.h | 26 + include/sane/sanei_debug.h | 93 ++ include/sane/sanei_pio.h | 55 + include/sane/sanei_signal.h | 50 + include/sane/sanei_thread.h | 33 + include/sane/sanei_wire.h | 104 ++ include/sane/stamp-h | 1 + install-sh | 250 ++++ lib/Makefile.in | 77 ++ lib/alloca.c | 493 ++++++++ lib/getopt.c | 831 +++++++++++++ lib/getopt1.c | 180 +++ lib/snprintf.c | 532 +++++++++ lib/strdup.c | 38 + lib/strndup.c | 39 + lib/strsep.c | 49 + lib/usleep.c | 60 + mkinstalldirs | 36 + sane-frontend.NEWS | 11 + sane.INSTALL | 21 + sane.PROBLEMS | 4 + sanei/Makefile.in | 76 ++ sanei/sanei_codec_ascii.c | 345 ++++++ sanei/sanei_codec_bin.c | 128 ++ sanei/sanei_init_debug.c | 133 +++ sanei/sanei_load_values.c | 198 ++++ sanei/sanei_save_values.c | 160 +++ sanei/sanei_thread.c | 108 ++ sanei/sanei_wire.c | 441 +++++++ src/Makefile.in | 89 ++ src/gtkglue.c | 1399 ++++++++++++++++++++++ src/gtkglue.h | 119 ++ src/preferences.c | 181 +++ src/preferences.h | 24 + src/preview.c | 1349 +++++++++++++++++++++ src/preview.h | 86 ++ src/progress.c | 90 ++ src/progress.h | 34 + src/sane-style.rc | 21 + src/stiff.c | 484 ++++++++ src/stiff.h | 20 + src/xcam.c | 1039 +++++++++++++++++ src/xscanimage.c | 1744 ++++++++++++++++++++++++++++ 58 files changed, 17042 insertions(+) create mode 100644 Makefile.in create mode 100644 aclocal.m4 create mode 100755 config.guess create mode 100755 config.sub create mode 100644 doc/Makefile.in create mode 100644 doc/sane.png create mode 100644 doc/sane.tex create mode 100644 doc/xcam.man create mode 100644 doc/xscanimage.man create mode 100644 include/getopt.h create mode 100644 include/lalloca.h create mode 100644 include/sane/config.h.in create mode 100644 include/sane/sanei.h create mode 100644 include/sane/sanei_backend.h create mode 100644 include/sane/sanei_codec_ascii.h create mode 100644 include/sane/sanei_codec_bin.h create mode 100644 include/sane/sanei_debug.h create mode 100644 include/sane/sanei_pio.h create mode 100644 include/sane/sanei_signal.h create mode 100644 include/sane/sanei_thread.h create mode 100644 include/sane/sanei_wire.h create mode 100644 include/sane/stamp-h create mode 100755 install-sh create mode 100644 lib/Makefile.in create mode 100644 lib/alloca.c create mode 100644 lib/getopt.c create mode 100644 lib/getopt1.c create mode 100644 lib/snprintf.c create mode 100644 lib/strdup.c create mode 100644 lib/strndup.c create mode 100644 lib/strsep.c create mode 100644 lib/usleep.c create mode 100755 mkinstalldirs create mode 100644 sane-frontend.NEWS create mode 100644 sane.INSTALL create mode 100644 sane.PROBLEMS create mode 100644 sanei/Makefile.in create mode 100644 sanei/sanei_codec_ascii.c create mode 100644 sanei/sanei_codec_bin.c create mode 100644 sanei/sanei_init_debug.c create mode 100644 sanei/sanei_load_values.c create mode 100644 sanei/sanei_save_values.c create mode 100644 sanei/sanei_thread.c create mode 100644 sanei/sanei_wire.c create mode 100644 src/Makefile.in create mode 100644 src/gtkglue.c create mode 100644 src/gtkglue.h create mode 100644 src/preferences.c create mode 100644 src/preferences.h create mode 100644 src/preview.c create mode 100644 src/preview.h create mode 100644 src/progress.c create mode 100644 src/progress.h create mode 100644 src/sane-style.rc create mode 100644 src/stiff.c create mode 100644 src/stiff.h create mode 100644 src/xcam.c create mode 100644 src/xscanimage.c diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..b4ed236 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,59 @@ +SHELL = /bin/sh + +VPATH = @srcdir@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = . + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +sanedatadir = @datadir@/sane + +MKDIR = $(top_srcdir)/mkinstalldirs +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +@SET_MAKE@ + +SUBDIRS = lib sanei src doc + +all: all-recursive + +install: install-recursive + +uninstall: uninstall-recursive + +clean: clean-recursive + +distclean: clean distclean-recursive + rm -f *~ include/*~ include/sane/*~ *.log *.bak libtool + rm -f include/sane/config.h Makefile config.cache config.status + rm -f intl/Makefile + +depend: depend-recursive + +all-recursive install-recursive uninstall-recursive clean-recursive distclean-recursive \ +depend-recursive: + for subdir in $(SUBDIRS); do \ + target=`echo $@ | sed s/-recursive//`; \ + echo making $$target in $$subdir; \ + (cd $$subdir && $(MAKE) $$target) \ + || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" + +.PHONY: all clean depend \ + all-recursive install-recursive clean-recursive depend-recursive diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..3439a59 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1062 @@ +# Configure paths for GTK+ +# Owen Taylor 97-11-3 + +dnl AM_PATH_GTK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for GTK, and define GTK_CFLAGS and GTK_LIBS +dnl +AC_DEFUN(AM_PATH_GTK, +[dnl +dnl Get the cflags and libraries from the gtk-config script +dnl +AC_ARG_WITH(gtk-prefix,[ --with-gtk-prefix=PFX Prefix where GTK is installed (optional)], + gtk_config_prefix="$withval", gtk_config_prefix="") +AC_ARG_WITH(gtk-exec-prefix,[ --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)], + gtk_config_exec_prefix="$withval", gtk_config_exec_prefix="") +AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program], + , enable_gtktest=yes) + + if test x$gtk_config_exec_prefix != x ; then + gtk_config_args="$gtk_config_args --exec-prefix=$gtk_config_exec_prefix" + if test x${GTK_CONFIG+set} != xset ; then + GTK_CONFIG=$gtk_config_exec_prefix/bin/gtk-config + fi + fi + if test x$gtk_config_prefix != x ; then + gtk_config_args="$gtk_config_args --prefix=$gtk_config_prefix" + if test x${GTK_CONFIG+set} != xset ; then + GTK_CONFIG=$gtk_config_prefix/bin/gtk-config + fi + fi + + AC_PATH_PROG(GTK_CONFIG, gtk-config, no) + min_gtk_version=ifelse([$1], ,0.99.7,$1) + AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) + no_gtk="" + if test "$GTK_CONFIG" = "no" ; then + no_gtk=yes + else + GTK_CFLAGS=`$GTK_CONFIG $gtk_config_args --cflags` + GTK_LIBS=`$GTK_CONFIG $gtk_config_args --libs` + gtk_config_major_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + gtk_config_minor_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + gtk_config_micro_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_gtktest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" +dnl +dnl Now check if the installed GTK is sufficiently new. (Also sanity +dnl checks the results of gtk-config to some extent +dnl + rm -f conf.gtktest + AC_TRY_RUN([ +#include +#include + +int +main () +{ + int major, minor, micro; + + system ("touch conf.gtktest"); + + if (sscanf("$min_gtk_version", "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_gtk_version"); + exit(1); + } + + if ((gtk_major_version != $gtk_config_major_version) || + (gtk_minor_version != $gtk_config_minor_version) || + (gtk_micro_version != $gtk_config_micro_version)) + { + printf("\n*** 'gtk-config --version' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", + $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf ("*** was found! If gtk-config was correct, then it is best\n"); + printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); + printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); + printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); + printf("*** required on your system.\n"); + printf("*** If gtk-config was wrong, set the environment variable GTK_CONFIG\n"); + printf("*** to point to the correct copy of gtk-config, and remove the file config.cache\n"); + printf("*** before re-running configure\n"); + } + else + { + if ((gtk_major_version > major) || + ((gtk_major_version == major) && (gtk_minor_version > minor)) || + ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the gtk-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of GTK+, but you can also set the GTK_CONFIG environment to point to the\n"); + printf("*** correct copy of gtk-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + } + return 1; +} +],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_gtk" = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$GTK_CONFIG" = "no" ; then + echo "*** The gtk-config script installed by GTK could not be found" + echo "*** If GTK was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the GTK_CONFIG environment variable to the" + echo "*** full path to gtk-config." + else + if test -f conf.gtktest ; then + : + else + echo "*** Could not run GTK test program, checking why..." + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding GTK or finding the wrong" + echo "*** version of GTK. If it is not finding GTK, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" + echo "***" + echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that" + echo "*** came with the system with the command" + echo "***" + echo "*** rpm --erase --nodeps gtk gtk-devel" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means GTK was incorrectly installed" + echo "*** or that you have moved GTK since it was installed. In the latter case, you" + echo "*** may want to edit the gtk-config script: $GTK_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GTK_CFLAGS="" + GTK_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GTK_CFLAGS) + AC_SUBST(GTK_LIBS) + rm -f conf.gtktest +]) + + +###################################################################### +# Configure paths for SANE +# Oliver Rauch 2000-10-30 + +dnl AM_PATH_SANE([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for SANE, and define SANE_CFLAGS and SANE_LIBS +dnl +AC_DEFUN(AM_PATH_SANE, +[dnl +dnl Get the cflags and libraries from the sane-config script +dnl +AC_ARG_WITH(sane-prefix,[ --with-sane-prefix=PFX Prefix where SANE is installed (optional)], + sane_config_prefix="$withval", sane_config_prefix="") +AC_ARG_WITH(sane-exec-prefix,[ --with-sane-exec-prefix=PFX Exec prefix where SANE is installed (optional)], + sane_config_exec_prefix="$withval", sane_config_exec_prefix="") +AC_ARG_ENABLE(sanetest, [ --disable-sanetest Do not try to compile and run a test SANE program], + , enable_sanetest=yes) + + if test x$sane_config_exec_prefix != x ; then + sane_config_args="$sane_config_args --exec-prefix=$sane_config_exec_prefix" + if test x${SANE_CONFIG+set} != xset ; then + SANE_CONFIG=$sane_config_exec_prefix/bin/sane-config + fi + fi + if test x$sane_config_prefix != x ; then + sane_config_args="$sane_config_args --prefix=$sane_config_prefix" + if test x${SANE_CONFIG+set} != xset ; then + SANE_CONFIG=$sane_config_prefix/bin/sane-config + fi + fi + + AC_PATH_PROG(SANE_CONFIG, sane-config, no) + min_sane_version=ifelse([$1], ,1.0.0,$1) + AC_MSG_CHECKING(for SANE - version >= $min_sane_version) + no_sane="" + if test "$SANE_CONFIG" = "no" ; then + no_sane=yes + else + SANE_CFLAGS=`$SANE_CONFIG $sane_config_args --cflags` + SANE_LDFLAGS=`$SANE_CONFIG $sane_config_args --ldflags` + SANE_LIBS=`$SANE_CONFIG $sane_config_args --libs` + SANE_PREFIX=`$SANE_CONFIG $sane_config_args --prefix` + sane_config_major_version=`$SANE_CONFIG $sane_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + sane_config_minor_version=`$SANE_CONFIG $sane_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + sane_config_micro_version=`$SANE_CONFIG $sane_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_sanetest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $SANE_CFLAGS" + LIBS="$LIBS $SANE_LIBS" +dnl +dnl Now check if the installed SANE is sufficiently new. (Also sanity +dnl checks the results of sane-config to some extent +dnl + rm -f conf.sanetest + AC_TRY_RUN([ +#include +#include + +int +main () +{ + int major, minor, micro; + + system ("touch conf.sanetest"); + + if (sscanf("$min_sane_version", "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_sane_version"); + exit(1); + } + + if ( ($sane_config_major_version == major) && + ( ($sane_config_minor_version > minor) || + ( ($sane_config_minor_version == minor) && ($sane_config_micro_version >= micro)))) + { + return 0; + } + else + { + printf("\n*** An old version of SANE (%d.%d.%d) was found.\n", + $sane_config_major_version, $sane_config_minor_version, $sane_config_micro_version); + printf("*** You need a version of SANE newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** SANE is always available from ftp://ftp.mostang.com\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the sane-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of SANE, but you can also set the SANE_CONFIG environment to point to the\n"); + printf("*** correct copy of sane-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + return 1; +} +],, no_sane=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_sane" = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$SANE_CONFIG" = "no" ; then + echo "*** The sane-config script installed by SANE could not be found" + echo "*** If SANE was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the SANE_CONFIG environment variable to the" + echo "*** full path to sane-config." + else + if test -f conf.sanetest ; then + : + else + echo "*** Could not run SANE test program, checking why..." + CFLAGS="$CFLAGS $SANE_CFLAGS" + LIBS="$LIBS $SANE_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return ((sane_major_version) || (sane_minor_version) || (sane_micro_version)); ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding SANE or finding the wrong" + echo "*** version of SANE. If it is not finding SANE, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" + echo "***" ] + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means SANE was incorrectly installed" + echo "*** or that you have moved SANE since it was installed. In the latter case, you" + echo "*** may want to edit the sane-config script: $SANE_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + SANE_CFLAGS="" + SANE_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(SANE_LDLAGS) + AC_SUBST(SANE_CFLAGS) + AC_SUBST(SANE_LIBS) + AC_SUBST(SANE_PREFIX) + rm -f conf.sanetest +]) + + +###################################################################### + + +## libtool.m4 - Configure libtool for the target system. -*-Shell-script-*- +## Copyright (C) 1996-1998 Free Software Foundation, Inc. +## Gordon Matzigkeit , 1996 +## +## 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## As a special exception to the GNU General Public License, if you +## distribute this file as part of a program that contains a +## configuration script generated by Autoconf, you may include it under +## the same distribution terms that you use for the rest of that program. + +# serial 24 AM_PROG_LIBTOOL +AC_DEFUN(AM_PROG_LIBTOOL, +[AC_REQUIRE([AM_ENABLE_SHARED])dnl +AC_REQUIRE([AM_ENABLE_STATIC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_RANLIB])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AM_PROG_LD])dnl +AC_REQUIRE([AM_PROG_NM])dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +dnl +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Check for any special flags to pass to ltconfig. +libtool_flags= +test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" +test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" +test "$silent" = yes && libtool_flags="$libtool_flags --silent" +test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case "$host" in +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + CFLAGS="$CFLAGS -belf" + ;; +esac + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ +|| AC_MSG_ERROR([libtool configure failed]) +]) + +# AM_ENABLE_SHARED - implement the --enable-shared flag +# Usage: AM_ENABLE_SHARED[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN(AM_ENABLE_SHARED, +[define([AM_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(shared, +changequote(<<, >>)dnl +<< --enable-shared build shared libraries [default=>>AM_ENABLE_SHARED_DEFAULT] +changequote([, ])dnl +[ --enable-shared=PKGS only build shared libraries if the current package + appears as an element in the PKGS list], +[p=${PACKAGE-default} +case "$enableval" in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_shared=AM_ENABLE_SHARED_DEFAULT)dnl +]) + +# AM_DISABLE_SHARED - set the default shared flag to --disable-shared +AC_DEFUN(AM_DISABLE_SHARED, +[AM_ENABLE_SHARED(no)]) + +# AM_DISABLE_STATIC - set the default static flag to --disable-static +AC_DEFUN(AM_DISABLE_STATIC, +[AM_ENABLE_STATIC(no)]) + +# AM_ENABLE_STATIC - implement the --enable-static flag +# Usage: AM_ENABLE_STATIC[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN(AM_ENABLE_STATIC, +[define([AM_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(static, +changequote(<<, >>)dnl +<< --enable-static build static libraries [default=>>AM_ENABLE_STATIC_DEFAULT] +changequote([, ])dnl +[ --enable-static=PKGS only build shared libraries if the current package + appears as an element in the PKGS list], +[p=${PACKAGE-default} +case "$enableval" in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_static=AM_ENABLE_STATIC_DEFAULT)dnl +]) + + +# AM_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN(AM_PROG_LD, +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC]) +ac_prog=ld +if test "$ac_cv_prog_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /* | [A-Za-z]:\\*) + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(ac_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$ac_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_SUBST(LD) +AM_PROG_LD_GNU +]) + +AC_DEFUN(AM_PROG_LD_GNU, +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi]) +]) + +# AM_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN(AM_PROG_NM, +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(ac_cv_path_NM, +[case "$NM" in +/* | [A-Za-z]:\\*) + ac_cv_path_NM="$NM" # Let the user override the test with a path. + ;; +*) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + else + ac_cv_path_NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm + ;; +esac]) +NM="$ac_cv_path_NM" +AC_MSG_RESULT([$NM]) +AC_SUBST(NM) +]) +##### end of libtool.m4 + +dnl AM_FUNC_ALLOCA +AC_DEFUN(AM_FUNC_ALLOCA, +[AC_REQUIRE([AC_FUNC_ALLOCA])dnl +test $ac_cv_func_alloca_works = no && LTALLOCA=alloca.lo +AC_SUBST(LTALLOCA)dnl +]) + +# @defmac AC_PROG_CC_STDC +# @maindex PROG_CC_STDC +# @ovindex CC +# If the C compiler in not in ANSI C mode by default, try to add an option +# to output variable @code{CC} to make it so. This macro tries various +# options that select ANSI C on some system or another. It considers the +# compiler to be in ANSI C mode if it handles function prototypes correctly. +# +# If you use this macro, you should check after calling it whether the C +# compiler has been set to accept ANSI C; if not, the shell variable +# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source +# code in ANSI C, you can make an un-ANSIfied copy of it by using the +# program @code{ansi2knr}, which comes with Ghostscript. +# @end defmac + +AC_DEFUN(AM_PROG_CC_STDC, +[AC_REQUIRE([AC_PROG_CC]) +AC_BEFORE([$0], [AC_C_INLINE]) +AC_BEFORE([$0], [AC_C_CONST]) +dnl Force this before AC_PROG_CPP. Some cpp's, eg on HPUX, require +dnl a magic option to avoid problems with ANSI preprocessor commands +dnl like #elif. +dnl FIXME: can't do this because then AC_AIX won't work due to a +dnl circular dependency. +dnl AC_BEFORE([$0], [AC_PROG_CPP]) +AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C) +AC_CACHE_VAL(am_cv_prog_cc_stdc, +[am_cv_prog_cc_stdc=no +ac_save_CC="$CC" +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi # Ultrix and OSF/1 -std1 +# HP-UX -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__ +" +do + CC="$ac_save_CC $ac_arg" + AC_TRY_COMPILE( +[#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, i +nt); +int argc; +char **argv; +], [ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; +], +[am_cv_prog_cc_stdc="$ac_arg"; break]) +done +CC="$ac_save_CC" +]) +if test -z "$am_cv_prog_cc_stdc"; then + AC_MSG_RESULT([none needed]) +else + AC_MSG_RESULT($am_cv_prog_cc_stdc) +fi +case "x$am_cv_prog_cc_stdc" in + x|xno) ;; + *) CC="$CC $am_cv_prog_cc_stdc" ;; +esac +]) + + + + +dnl aclocal.m4 generated automatically by aclocal 1.2f + +dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +dnl This Makefile.in is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + + +# progtest.m4 from gettext 0.32 +# Search path for a program which passes the given test. +# Ulrich Drepper , 1996. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + +dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN(AM_PATH_PROG_WITH_TEST, +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + + +# lcmessage.m4 from gettext 0.32 +# Check whether LC_MESSAGES is available in . +# Ulrich Drepper , 1995. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + +AC_DEFUN(AM_LC_MESSAGES, + [if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES) + fi + fi]) + + + +# gettext.m4 from gettext 0.32 +# Macro to add for using GNU gettext. +# Ulrich Drepper , 1995. +# +# This file file be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 3 + +AC_DEFUN(AM_WITH_NLS, + [AC_MSG_CHECKING([whether NLS is requested]) + dnl Default is enabled NLS + AC_ARG_ENABLE(nls, + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) + AC_MSG_RESULT($USE_NLS) + AC_SUBST(USE_NLS) + + USE_INCLUDED_LIBINTL=no + + dnl If we use NLS figure out what method + if test "$USE_NLS" = "yes"; then + AC_DEFINE(ENABLE_NLS) + AC_MSG_CHECKING([whether included gettext is requested]) + AC_ARG_WITH(included-gettext, + [ --with-included-gettext use the GNU gettext library included here], + nls_cv_force_use_gnu_gettext=$withval, + nls_cv_force_use_gnu_gettext=no) + AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + dnl User does not insist on using GNU NLS library. Figure out what + dnl to use. If gettext or catgets are available (in this order) we + dnl use this. Else we have to fall back to GNU NLS library. + dnl catgets is only used if permitted by option --with-catgets. + nls_cv_header_intl= + nls_cv_header_libgt= + CATOBJEXT=NONE + + AC_CHECK_HEADER(libintl.h, + [AC_CACHE_CHECK([for gettext in libc], gt_cv_func_gettext_libc, + [AC_TRY_LINK([#include ], [return (int) gettext ("")], + gt_cv_func_gettext_libc=yes, gt_cv_func_gettext_libc=no)]) + + if test "$gt_cv_func_gettext_libc" != "yes"; then + AC_CHECK_LIB(intl, bindtextdomain, + [AC_CACHE_CHECK([for gettext in libintl], + gt_cv_func_gettext_libintl, + [AC_TRY_LINK([], [return (int) gettext ("")], + gt_cv_func_gettext_libintl=yes, + gt_cv_func_gettext_libintl=no)])]) + fi + + if test "$gt_cv_func_gettext_libc" = "yes" \ + || test "$gt_cv_func_gettext_libintl" = "yes"; then + AC_DEFINE(HAVE_GETTEXT) + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl + if test "$MSGFMT" != "no"; then + AC_CHECK_FUNCS(dcgettext) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + AC_TRY_LINK(, [extern int _nl_msg_cat_cntr; + return _nl_msg_cat_cntr], + [CATOBJEXT=.gmo + DATADIRNAME=share], + [CATOBJEXT=.mo + DATADIRNAME=lib]) + INSTOBJEXT=.mo + fi + fi + ]) + + if test "$CATOBJEXT" = "NONE"; then + AC_MSG_CHECKING([whether catgets can be used]) + AC_ARG_WITH(catgets, + [ --with-catgets use catgets functions if available], + nls_cv_use_catgets=$withval, nls_cv_use_catgets=no) + AC_MSG_RESULT($nls_cv_use_catgets) + + if test "$nls_cv_use_catgets" = "yes"; then + dnl No gettext in C library. Try catgets next. + AC_CHECK_LIB(i, main) + AC_CHECK_FUNC(catgets, + [AC_DEFINE(HAVE_CATGETS) + INTLOBJS="\$(CATOBJS)" + AC_PATH_PROG(GENCAT, gencat, no)dnl + if test "$GENCAT" != "no"; then + AC_PATH_PROG(GMSGFMT, gmsgfmt, no) + if test "$GMSGFMT" = "no"; then + AM_PATH_PROG_WITH_TEST(GMSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no) + fi + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + USE_INCLUDED_LIBINTL=yes + CATOBJEXT=.cat + INSTOBJEXT=.cat + DATADIRNAME=lib + INTLDEPS='$(top_builddir)/intl/libintl.a' + INTLLIBS=$INTLDEPS + LIBS=`echo $LIBS | sed -e 's/-lintl//'` + nls_cv_header_intl=intl/libintl.h + nls_cv_header_libgt=intl/libgettext.h + fi]) + fi + fi + + if test "$CATOBJEXT" = "NONE"; then + dnl Neither gettext nor catgets in included in the C library. + dnl Fall back on GNU gettext library. + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions used to generate GNU NLS library. + INTLOBJS="\$(GETTOBJS)" + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], msgfmt) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + AC_SUBST(MSGFMT) + USE_INCLUDED_LIBINTL=yes + CATOBJEXT=.gmo + INSTOBJEXT=.mo + DATADIRNAME=share + INTLDEPS='$(top_builddir)/intl/libintl.a' + INTLLIBS=$INTLDEPS + LIBS=`echo $LIBS | sed -e 's/-lintl//'` + nls_cv_header_intl=intl/libintl.h + nls_cv_header_libgt=intl/libgettext.h + fi + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext programs is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + + # We need to process the po/ directory. + POSUB=po + else + DATADIRNAME=share + nls_cv_header_intl=intl/libintl.h + nls_cv_header_libgt=intl/libgettext.h + fi + + # If this is used in GNU gettext we have to set USE_NLS to `yes' + # because some of the sources are only built for this goal. + if test "$PACKAGE" = gettext; then + USE_NLS=yes + USE_INCLUDED_LIBINTL=yes + fi + + dnl These rules are solely for the distribution goal. While doing this + dnl we only have to keep exactly one list of the available catalogs + dnl in configure.in. + for lang in $ALL_LINGUAS; do + GMOFILES="$GMOFILES $lang.gmo" + POFILES="$POFILES $lang.po" + done + + dnl Make all variables we use known to autoconf. + AC_SUBST(USE_INCLUDED_LIBINTL) + AC_SUBST(CATALOGS) + AC_SUBST(CATOBJEXT) + AC_SUBST(DATADIRNAME) + AC_SUBST(GMOFILES) + AC_SUBST(INSTOBJEXT) + AC_SUBST(INTLDEPS) + AC_SUBST(INTLLIBS) + AC_SUBST(INTLOBJS) + AC_SUBST(POFILES) + AC_SUBST(POSUB) + ]) + +AC_DEFUN(AM_GNU_GETTEXT, + [AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_ISC_POSIX])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_C_CONST])dnl + AC_REQUIRE([AC_C_INLINE])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + + AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h string.h \ +unistd.h values.h sys/param.h]) + AC_CHECK_FUNCS([getcwd munmap putenv setenv setlocale strchr strcasecmp \ +__argz_count __argz_stringify __argz_next]) + + if test "${ac_cv_func_stpcpy+set}" != "set"; then + AC_CHECK_FUNCS(stpcpy) + fi + if test "${ac_cv_func_stpcpy}" = "yes"; then + AC_DEFINE(HAVE_STPCPY) + fi + + AM_LC_MESSAGES + AM_WITH_NLS + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + dnl The reference to in the installed file + dnl must be resolved because we cannot expect the users of this + dnl to define HAVE_LOCALE_H. + if test $ac_cv_header_locale_h = yes; then + INCLUDE_LOCALE_H="#include " + else + INCLUDE_LOCALE_H="\ +/* The system does not provide the header . Take care yourself. */" + fi + AC_SUBST(INCLUDE_LOCALE_H) + + dnl Determine which catalog format we have (if any is needed) + dnl For now we know about two different formats: + dnl Linux libc-5 and the normal X/Open format + test -d intl || mkdir intl + if test "$CATOBJEXT" = ".cat"; then + AC_CHECK_HEADER(linux/version.h, msgformat=linux, msgformat=xopen) + + dnl Transform the SED scripts while copying because some dumb SEDs + dnl cannot handle comments. + sed -e '/^#/d' $srcdir/intl/$msgformat-msg.sed > intl/po2msg.sed + fi + dnl po2tbl.sed is always needed. + sed -e '/^#.*[^\\]$/d' -e '/^#$/d' \ + $srcdir/intl/po2tbl.sed.in > intl/po2tbl.sed + + dnl In the intl/Makefile.in we have a special dependency which makes + dnl only sense for gettext. We comment this out for non-gettext + dnl packages. + if test "$PACKAGE" = "gettext"; then + GT_NO="#NO#" + GT_YES= + else + GT_NO= + GT_YES="#YES#" + fi + AC_SUBST(GT_NO) + AC_SUBST(GT_YES) + + dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly + dnl find the mkinstalldirs script in another subdir but ($top_srcdir). + dnl Try to locate is. + MKINSTALLDIRS= + if test -z "$MKINSTALLDIRS"; then + MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" + fi + AC_SUBST(MKINSTALLDIRS) + + dnl *** For now the libtool support in intl/Makefile is not for real. + l= + AC_SUBST(l) + ]) + diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..413ed41 --- /dev/null +++ b/config.guess @@ -0,0 +1,883 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# +# This file 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# The master version of this file is at the FSF in /home/gd/gnu/lib. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]` + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; + amiga:NetBSD:*:*) + echo m68k-cbm-netbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:*|MIS*:OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:NetBSD:*:*) + echo m68k-atari-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:NetBSD:*:*) + echo m68k-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:NetBSD:*:*) + echo m68k-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >dummy.c + int main (argc, argv) int argc; char **argv; { + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + ${CC-cc} dummy.c -o dummy \ + && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ + -o ${TARGET_BINARY_INTERFACE}x = x ] ; then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[3478]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/7?? | 9000/8?[1679] ) HP_ARCH=hppa1.1 ;; + 9000/8?? ) HP_ARCH=hppa1.0 ;; + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo i386-pc-cygwin32 + exit 0 ;; + i*:MINGW*:*) + echo i386-pc-mingw32 + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin32 + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >dummy.c </dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >dummy.c < +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; + R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..55704e9 --- /dev/null +++ b/config.sub @@ -0,0 +1,958 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 \ + | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \ + | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \ + | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | v850) + basic_machine=$basic_machine-unknown + ;; + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[3456]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[3456]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* \ + | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \ + | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[3456]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[3456]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[3456]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[3456]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + np1) + basic_machine=np1-gould + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5) + basic_machine=i586-intel + ;; + pentiumpro | p6) + basic_machine=i686-intel + ;; + pentium-* | p5-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + k5) + # We don't have specific support for AMD's K5 yet, so just call it a Pentium + basic_machine=i586-amd + ;; + nexen) + # We don't have specific support for Nexgen yet, so just call it a Pentium + basic_machine=i586-nexgen + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + # For sys5.3 apollo + -sys5.3) + os=-sysv3 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-ibm) + os=-aix + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -hpux*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 0000000..caf110e --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,109 @@ +SHELL = /bin/sh + +VPATH = @srcdir@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = .. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +configdir = ${sysconfdir}/sane.d +sanedatadir = ${datadir}/sane +docdir=$(prefix)/doc/sane-@VERSION@ + +MKDIR = $(top_srcdir)/mkinstalldirs +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +LN_S = @LN_S@ + +@SET_MAKE@ + +SECT1 = xscanimage.1 xcam.1 +MANPAGES = $(SECT1) +DOCS = sane.ps sane.dvi +LATEX = TEXINPUTS=$(srcdir):$$TEXINPUTS latex +DLH = TEXINPUTS=$(srcdir):$$TEXINPUTS dlh +MAN2HTML= nroff -man |\ + man2html -compress -title $${page} -cgiurl '$$title.$$section.html'|\ + sed 's,,

,' + +all: $(MANPAGES) + +%.1 %.5: %.man + sed -e 's|@DATADIR@|$(datadir)|g' \ + -e 's|@CONFIGDIR@|$(configdir)|g' \ + -e 's|@LIBDIR@|$(libdir)|g' \ + -e 's|@BINDIR@|$(bindir)|g' \ + -e 's|@SBINDIR@|$(sbindir)|g' $^ >$@ + +install: $(MANPAGES) + $(MKDIR) $(mandir)/man1 $(mandir)/man5 + @for page in $(SECT1); do \ + echo installing $${page} in $(mandir)/man1/$${page}...; \ + $(INSTALL_DATA) $${page} $(mandir)/man1/$${page} || exit 1; \ + done + +install-docs: ps + $(MKDIR) $(docdir) + @for doc in $(DOCS); do \ + echo installing $${doc} in $(docdir)/$${doc}...; \ + $(INSTALL_DATA) $${doc} $(docdir)/$${doc} || exit 1; \ + done + +docs: ps html + +sane.ind: + touch sane.ind + $(LATEX) $(srcdir)/sane + makeindex sane.idx + +ps: sane.ind + -rm -f figs; $(LN_S) $(srcdir)/figs . + $(LATEX) $(srcdir)/sane + $(LATEX) $(srcdir)/sane + dvips sane.dvi -o sane.ps + +html: sane.ind sane-backends-html html-man + $(DLH) $(srcdir)/sane.tex + +sane-backends-html: + cd $(top_srcdir)/backend \ + && emacs -batch --load $(top_srcdir)/tools/sane-desc.el \ + -f sane-desc-doit + +html-man: $(MANPAGES) + @for page in $(MANPAGES); do \ + echo "translating $${page} to $${page}.html..."; \ + cat $${page} | $(MAN2HTML) > $${page}.html; \ + done + +sane.tex: sane.ind + +clean: + rm -f *.toc *.aux *.log *.cp *.fn *.tp *.vr *.pg *.ky *.blg *.idx *.cb + rm -f *.ilg + +distclean: clean + rm -f $(MANPAGES) + rm -f Makefile *~ + rm -f *.lot *.lof *.ind + rm -f sane.dvi sane.ps + rm -f sane/*.html sane/*.gif + -rmdir sane + +depend: + +.PHONY: all install depend clean ps html htmlman sane-backends-html diff --git a/doc/sane.png b/doc/sane.png new file mode 100644 index 0000000000000000000000000000000000000000..d8a98901040e3c5aff8260b416e321b8c3da6198 GIT binary patch literal 10753 zcmV+cD*n}pP)+GBcBsncFYyuq3&CSXNGm{1+t2o--001BWNklY%`0qWyqP|~09#vhRwwujsy57!XGwybW`*6Qp zp0L=$x~`JNZoPhd;1B!l=Jo2@xY!T8*r8O{(Bggo!4C)Dg_2*x?G_f-6D@Auq{9#w zf4aIJ46MDH^Z6VWU))o4hO23Z+V-Tz26Xly`Fb5ljRP#cT$&aaqrUIso8F!Q!Jku8 zpB%2e8IlZ(FPDo)=zQf#w1LIz^&1yYpmKwY&%@a4aPf3mHMIC$PsjK1cpU0AzP-=s z*Yc4`RprP3vbY_F0}aQYFOKMDA=9g z+SGu>bOYeVsV0>Hjj;GQ4RGrm!e(&swgKF_J=~J9tLg3e%ZeBG{jvA!b=M#g&;GRC zZYIVJ7Vj$50>I$K^#E7n;mvxyYW@vhYv_;kLIZ#I#Jay=sC^3o;g85h;9QIUZ|Jw$ z8Tg$TOq_e-P3iDk;if#`-V7(?oW0%7rbc3P1~hJ0#EW5qZ@{%{AT#~}-r?qoWHvS4 z>#l~kCu`r0!?m_Wm_Mitak)FkwRKwC*GE|U?r@KM;7&ET_BJHBw#BsrEp|0hsJFn) zQ(If}AtuMQ_F|d=aA=wK6|VJgLp}ynXo#Dh-`kh`rsM ztnIpssbKB9MXnu>9RY@1JJojc@-HOYV2D3mZOm#~)j;3oh{SBx>-F=4iwC>ew4lOm zY>{hsSX&dmu&!x=mTQkU-@@=Srd{yM6ulY4(V~x~oh@^kR$-lL*WD4J% zvuujq#`C|y{sI^uK#`XI?%=I#$>upk|As(;83c0%_iJ}Q7`VN_$IHqLD0eU7oY3g~ z9OQ@gYZMG}JN`+C(Po2!jlZ#6)6{@0S)D`YhmqtyTi$O$&!%dXT<{ZX7W;Uy!VT+- zbaixFSuW{|cMN{|g!ZA3`+iSg58p?YYkT8aDpIA7RTLhE7Ecd|gstt1MBp0Eb zST2D3oD9o-e4Z2jq|f9@D(!=Ik5(+ny`#PsHjsB6%dICRxviUtOb~!;_9zzj%Eyr* z=%zi%#eHy{?0F3O9!Rc5GuZ*%gb#J&L@KxhGXyU5-4NuS@IBh?wi|F8pxE2_Ikcqj zPSm}3;{^mWWFXgr17#|pqk&&!DFYQgv|CRbxN~;1-GE?{3!D7b4c(dK9u6$m58Vpn zTDH}mZdl!t`#OS4=pCVeCcr#c?CAsoEZ#HY&6V|qo90JHa?vi_FZiCkv*Es>+#}qu zL8O8Q^QNZ_@tisldxAS>>82TfV(OA$c+){$;+Y>|$6r`3D+)L4&0@FYMhOG6XQ{w1 zcz?vOmuXn+h~^{6J+QtO=^N$p`|pMtrLJKc_Hw^I-EjJdV7_IDt!r3Y*l43egGcHD z6VQ^aqTG7wo^+XMGM#Y)1~VOBX7cHejp23O)Hr#ugL@oTxGDT;s{gI_>_1GbHSf2# zay8-KT)6lZAOG&_^e2uu9K;y=D4>$Cne5Gw>;qr#UW_DL`RcSiu`%0Bd$H-T<5oPtH~rk1ruvBC7hb|xQ$R%ewAuWOoj2!#>Kx>+*_!Js!mSx|SlW?~PdEm%a< zmc)AHCfJ;@5Zg3C*@yTE8?=3OgQ3kvV#!~kwrFWFK1H!r6bl=8O4^!s=tU}QcEbih7!?SlZEbxw6N~V= zBWnxy%h}-6PIS*sgWqh$t6kgSra;(V3AyK&luVh-80w?t|7lpd%^jU3C7_91bW~l zR#7bK*M?{T^EaXwZrrzd1jmlxZpryDvLF|>#29P>W9ziG4(=1icSru}5yyScAt?z( zhlZ{dH-l>=x&dI_5X7R;JKKb3YgZGC1wmjAjz`w^=o-f0@rW3lFhWDI#<#B+EDT_C zL@X1mYFE#_@YZ2CN}&QvMRgsSgH2~25-i|7+n}v&y+kx#ZJ73zolX0@kU|(UF zG_lP7cm#L^0%JpHgZGRKg2XlyD}agi>Xz{~0-xTAwr>bPsAR@mw+^fc*}gpV&#@GrjYd0oq9U^5X*IPHi+Fg0Rc>{jZqjzbOP;VbghJ8B9`BK zKeZtB{B(_HD~p!PhoEs|nqa#qx*JEVga8Vj#KQg>+Z8J-_BO<94$_Lwv`t;5*sW>P zA0-IvOcSFx%nZT`(}r(jdy7fyK-H866IpaxUanAr;S4vfi!b_YaS+t}hlO_k8}Y5j zpwIuwxB2p_e))I5^y(i9ThJEtjM2iRohHXozRA9A-?N>UC=GYzG^8Km@>-H~5Zq6=lzuK-Cf#?I_;Zkq>_w$eTdLs4e8DxKC5=5U-PIeKWL~ zw$D;q+edUCd|gpoxSCef1x-0@+mN~gD=P|*PpvHhD*+NNZM!?^yQ1VYX={u7jxw4_ zhh|SR>B{?Sq0e!GqOzT^VAlzN>R+N7=U_8^|-fZEomuRse-=mcBu-m}Xg zypaw^t*y5`*jyVonJ@t|45#hM@L}3+qqeZYKwZngaz+!e9d~Mz9S%X1pPYD{?@VBL z2VA^>Er$PKHVh*hRK>EHnKW63L zIBy81l(u9I;K%G04?Y}TCnIK0E!a|<)0Rx_(@jHrF0jR27PLJiY%Qiv#vsIc87$4D2ny&+3LPMiJ5VO4eMWEv2oZt!PWS5(PXM zD1%GIJLL8%^9s1zoNI^N(851(Ml9fR<`UnO1^Wf+daJMvZVc7!3f^Y+i?n53F?B*? z0HM?1mFM;CH+ZS-5D976E5Oeg-Va4u4BL|tBVPuf_!g4cP^%VgN!=F(vf6?n6C$>t ztJIU20<);5bYE{S6(2K?N@bx0?jy05s+=1#)Uo`6>Y9yWfy4;#`an^4q3uC(CfH@? z7$eNIm1wA-!;uumY^9BMl%OTA;9A^g30cmxp7Pc#dos8&zAK1;7wq4?@@0y&_q%up z*Kw(CL0k8pC>n}%IPxX`@7=)PP}vyE1WWsgG$3t-3Re6Ws5_iCuY{`@FEqOe+g-lL z?i?pLld!c@(^N@YFt3OTY$yhmHD56EJ&0q_!QzwE z?XjDQPPG}8lYauyxF4zQiy{r+#%c#C%-+A)e{rhwL-f z-hwso?PxM>BecOgRK7K<&e#qU-e_+bRCmGF>pv!5VOJ2EJmPuv#r^n{GZ8 zDw-)Oy2gH2XDH|jhJfxr`m>Hy)%r5Sm9iAodZRcSu3%|`vXKg;?cP#f@3O!IZpMXT z5C#V}stU>?M_VSrns6mcfZ!_1^7W#KBxX0)r0)5w)IGDh#M^`9W8Bb#U&sXOC?8v` zzGzF<>L~WgTTvBtMLT45jr2p!W!O3!F11OT6Tby z9cf!T_!meW;WfFQ#&q3t+{N-GzLetIp``{L{%7DqL+FR8ZC%@fPnPc9)Vln_f<`lx zFXO8<3M5$$rLkdM5WpTCetcVq7>21>JNYaI!~ZJuzIF5ertnoYq*(KxU$y&3+kcz3 z6&6JI)xT5`{jDHcExcU)nXpA|y|t|*VzGB0TKG-z7Aot?D=V4K|Jm(9Mmu{gtTw?Q ziLg=w+cZV}Hq;rxuFT4}lV2(^>LO#Sm)PXmV%e^h$T80#q<%Y&I@!6mQx}W3;?8L4 zDgv9ba!hB7#5bfmU$n)sG^c8ImOa}k=!$L)WpsJ5xs%X+%*!A5JNTn9)tboxQ%tc6 zcQ$H9#h;=YqBFUqtuBo}PI`$Cu2>37OsLHqPDOARJ21VlB;dCQy&r%4Jz%XbVqZ^FwuxT6=hLGVI zwcXpYYF{Mlmr`5*j@pKyv`pJQ@t`Q+3b=_0rM6*o0JZg`uBzlmZS$fXvZ>0saPJCj z>sDjS?ND88_NMGQ2)I|8s|&MVL0erBMcz_iG?~O(tT9R(&f9WN6_xQh6Y5l02u#S= z>`$rj5VgfT_j*-fdDM2CYm4`n+YZtt5p4Hvsqdf*O_y%2Z69V0fIu2O6t~1{5 zN}C|8@@*GwZse_9Dui;Kc}ZLA8sEq^3)Ys?G+o{sKBugZAKDK4Te4syzd@RMidF%= zL)ZgJ-NakFR2KKD>riOhgWqag?Cpi*C-3PrHf}PRp2Ds^R+^Kt854G@rxQgD?U=Ov z#)MQA=ZaXNE!Nb)DKZ>n5q>fHXD9MOL<|Ydk>bJWb+qxP;E*W>(V%LFuE$_4= zYU_2E#I%F$^A^761 z2tI!wi;dCZrfp_%dTSp;8ccsV_kD2(YRM+V+PKEHw!_37zQ}~yee39elQ1O{kOF8q z-)DdVekdLl1ZND|3e9b;hGofN_Tkpzt z*+;i@ron4)H?gBb{jziJ%hD#3(p@ZCx0h85`7mo6svkf0pQyPPwcWQgDAalxmlADJ z-*dbJcKc~30GG_IqHQo@64YpHleUMbt;JDRh#s*WNz7cawOLjd7gR`HwcV*a-gnZA z6tBxA=j6@o_T*gZ?x~^;?z32ATE;eNOUhnwV}iOWVjSM@pLW`@Q`$<&5w_W^`H*Uy z5P@-rBqsuQNc{f1q-`pRlC~8qd!agS%M-u#L%MgLyl&iPY5tdb zky+bR#vc(}t~i%Wh+Q4j7L>hnFOteUx>obOw@1;1i)oA{ABN>z-ewQogGyT&2Q;zt z73`O4n30D#&wN>`=CihlEJa{XviyGVRn)c`7OmLvElcBwkEO!i`h=zOL6Cx!=Dy3MfF-7?me8mF!(jfOsN#suxjSX&oM zxhpknpsOF#5)*{FW#^Q-(tT|2g`QcE%mY@`eBuBsOeavdNWHRiiR~fupvZ#7@v4;$ zL{(*JVW;u%ur3sYF)+09=Apa&W#e=sUFp|r*65WsZ<*<&j{nmb&4l74pX{`DrYrv5 zJ3UjgW^H@d?(L&gH*7Oz!iIWJng^0LkP#aTn-EJMq^&bwd28QPX42{&V`o}Zmzz*) zjK0v-Nf+Xg+IzCitQ;gH55bZ6OLZg3L(H^Q{XH;{)Z@hzl9*sKZ9!}`-)W(X7NZ2K zXV%obQlvs`O0%{J+^mhx;GV~)wqQY9i5MwTl)x5HT2bLJ#9*!^OEqQCzC%|kTKz0x zSmy>oh+9Q%x0@HW&@&!2qt2xPj4 z9!Ko5R&Q*fOS%i{csg_Nins>m4&7O6d(ge!P)`^+#lilmi&Z-toh(xKm`K3j#`%Q3 zQ^OR>=_YWmQilt{7r9?OoFF+F&nI+7X{%^^k$S@5Am!~0bqj9c!4lWz}khUMY zG>#S}F^79(OK8J3v$04+lR(;faoR9q4l#D}-b&hr__jfHJMQ*&nYKrsrmFp3Z7*s1 zANvmnoV}W}#GwpsO6J-Q8e1Mu$h8gAp}sXr+pOsy>^7<^t?ABWRlBhDk-8dIZc!p; z6vxDx2ewnYfb1vVW@^ZeJVZHH13?0q#lf)SvCP^K(%_RV!nSUPmU`1vW7Knu$1wXv z-TrrKQ}>cAfZI*`i$*^N_b5g`WSiNPGo)dPY(xReG#J`7wVM67hsJcu@H~yF=sFl^ zD?rMqiU~dHs4ON6mCdG=sDu6}lofAgRdErGSjTlx1?`AKVG`OE(-ar2t#zwd5e-ZT zx1D!dGlcdQ$_UU- z<2jXt?HUK7Y!Mw`Zf00jHK`H?RkD(JGn7L>anO!tKN1r%?_j&wF4KJn?Fk&$JoISA zdVT4lwyGE|Q$QIPUNp$JQ4`oSr_yF7Aseev*xoa2VTYwF=j|~Ls~|xt##*F;X!}WfjPsky#>707#BpZntgkc#6eg_1>tdITERa=GHJP?-0Ros|W>K`o zGiO2sRqfzywl8=<6IKI1zd(@XY7)<{o#QkZwa7v=ob!OSMRTC1fHEdTj-uWauh}?X zwYhX`zf$xqrTdmzH~EAW;j-bgF4u*Tr7_M|?LvGR>j-?52zMC{gIx+Hgk7d}<%uP@ z5n*`sN~cb&i}7~|6fsM*r)O!#gI$!9(A`L>}&{jVAg>3e&dycbLn@u1BV~c5H)0%F4KJ&>jvSAGl zip2v(JSWz5-BV)T%i+S)cfy1UG?V9P@PSHHaA{aGMREEsvy$Ko@0Fb8|lDHZ0G@ z0an9ot(yH9iVN$ubeObJN8HM39sD<0R=gU|rzUyu+FZa_$#qkxL~B)LiD!N2x9Wdn z9;)H1uKzp3dyW3?f2P;|x&DFn{}NjN4?zFJ&{pw*OO~GA2-aS`^yT`4sZ#svwg17+ z|G~F|s+CCiZC(C@{y;E%!`}W42&*sepg1uPPTQOJFBiJTA3Y#7F;k|u?o)+54rFxn zK+k1por+Ai*@^s38ZR*{pptpXRL;@~A^dV$T`RLE)Tt-^K_$IV{xycG&)sMtc- zMtslw#pv=0i7JCuu+1MfAjlr@8zvmGy##pg3fh2e0%27GyU;oPJSiF5|D?l6b=o4mujVF)zt?%a0?(}Th;m+Rx*qQ~S5G_IiAv-x>f5xn7FiZLYT1t!k zkB;oEfnE2yB@nLXH`-Q>?X%()+XH26L*twDgk*twDs?f ztYmF6wNz^FLY-xX?SR;BGicRGiUjRT2xiUoiyI5jHj%Z-8iXl{3|e8W$Ahg{4;i&d zNN!A^Rjl1x`-_W08gMaV`T{OP>+4@F0=cnupY`Asv@hBui*f*4f%OzPt1Uu;_Db0L z!FJl#Mra}W+7+xF(-8QKwfAHY7y|$yj-(`Dm!Y-4MOJTe4J7xQJNpi8wU3*ljaByI zxmW4j^+#L58MbZi#O474L;DKYo|e7X+}5g~c4iRh@rwEz5QH@ElR;~8TkC&^_T7`N z4NcpDn_P5bZrLEfo-lZ1w5sDd=5-2bGlLMI{bE_FX5W_9U@I<6_cs)_8x3tTwxz8t z;)8>lK*^v@h9CV|79S*Nm96#Gy??*pn}`urHlQSFZ-b@n7wo}DT5n&|2K>o;^Cdpe_JBs{kqV%wHnra(gx$;_C}Y4+ z(#ly|2fs5aCw7?|g!<2*#nExc#6?S9ScPw_MQejkVZd+o;Kd1_a9y%Q~EMZNx4?Yv$S5A7dMdOU5Q*drXPQ5@~_9 z9LHOJv|ztzX$4y;Bvgft;qwg1=h~2L6I=bSqs48Il=+! z3eJq*Si5j0_E+Lo+zln-9={p{Z$l~Zv`E`LI{1mU7N6q>?*k)^p`F)iH!1K+r&MC< zkX01%YgV4gOhSwh?h7e{0`_vDhBJ1hL+~|&w%MEa-w}5Ri3zwf9CTZ*Az3=GZ}<#!PX|yCTLx5XxD`g`+RX^mYDH;I`&y_J@N3V28Y-rzqN8HJaRUqPa3-wyc7DADhE$Fbf>-A5D zHW=G7lCyk>J-ibLZ|6=dGqhYjc!tzLyRk)sP{g(BajVMKHu#L01S~)+b-{+fb+OHm zJ(tG+SdRTd+={;w+?g?R`?yb}T?g6@I86A+k^N-Qo<67T+>rsaTN>ppu`L3x0B$JE zQ0f5wuT7Nw!rFLzI6c1O9%8QmEi?9>K`Sl>!9`!N(7@pU_|LIDQp=2qOV8nI#YSj2 z-U`|i*R*UKTMO$27sfN(b4SL|GH)lwHUhhuBb!<`A-ruhX_xA?^ZG#nZ5x19rP?g! z1auqeny$)B=dXx+1{152RfSZTB<-`YUDDu;P*ee zFtgyq>* zy8^T`+A3(b6jEX8U}u(g4lRJ2QU`fX>D(YJLz_;8psh7y+00#Cz7_mZqFZI){$v%7 z>5EVB^eOY5rMLyO+*2H^n*|3YuyaQip~VbW#ub1C8=Wj9WUu-B!84_08EfkWXb;+t zY1ZP*a5snc7h4N%+a_Dtd~e+zDXC4^@~P7$;-+jtH5tQnlx{1O!GS=#DVpyAS}u8U zH5Rcg>$J;LGck2|EgFQ_%RR{4j5^0-(NV5~xR%;r3ETc_g?46WKN)SSFVGg)e)nM^!+nO-;S02L9~L98l#M|`K;W7& z#-Jcff$RW!I3b7FYU0ArTF;HaVmKSq+w35%K$~c5 zZ2&etVn3!1IkdNHF?=A{#;yY%SL&AH+QaUPJ-Fv{2wqCGfwed<#~;jQTscms8jmS` z<#u}x?NNRBKm?YdeQ2W~q!m!r+}v)*2eJCc&jOsRD(xbT_peIqwuS)o7HP|PgkX{)Dboc(|7jZ zgkEtLes#(3?5$lU?D|acN(b?mc3`LC@b_sRe_5N8_LZ<5>?viqH#I>=$fknVErqu{ zG^}d~U!2$>XKkgz|H+vrK54>+WBZHs+63)UH*Uksfer@LN0A7s{4Dw-K4UB7{g^Ej z{l)P7{3iv7_#qXgnLU-@W{%8S-Nb$ICjumFvx3)kX*iKSFoLn&V<44gm#rO_vxS)( z)A2ursPIPQqcB#hr4bK?HYQo`EDI29-x}3E12%pjMPwPJxJ#VH2SAXk-dpp@{?v=X)Amm)5*!W8y(##wngOTqc9w^g zmUiT)F_^OCkr{+tYTKj(`j>gLTteAPhV3_lkR@3Nu4*G7ar^LS8qHY!VLBIXyX>*E zxL{?&gEhjc%or>}3-Oooj0*$cGN(-ELIB&WBvXtg3TyEbuv{^AuAn{aW{KEECA#t3 zDz*jrf&H)0YEKnn0Nq9)Z`K!{OMmjumIV)19;LC!*-x+t5RI}iShTY76M|G9bzxM7 z%3U#aFgotKl`bqmJI?x}*3Ktp)H53BTu9E^XbUoP@Xa8^m^I6`l2yRAq)DhAv!^If z=CxwXtZIidutgJ0=DxuqoW6wy;l#oz9cc;BzUF-e!Ip=>eai74RL} zCQ!CZ2N-^bc6RllHZa7lxa}7R%fR*r>d8-(Ev&zmxgOFAr)I-E1IwVrkEn>WP0%XN zN{u##w_O&|rWr2 zash3(2yLIo0LiZEgA8$IBg3^{9|Tz-ZJMLcVU3CHhJ&=d{YKfXa29(tPqFt4(56CS zO3QTAbz86o;ZZL7Xl4fOeI9segMdeE)r9@!kDv_?rW3MefoqsUsv0$ElyL30t1zKs zQ@=JpS)&u%5ZZR9ubd5sY_?%)#oAZFS>3To9i13--4=ZqpT-@tLzUL%M{;%TAcq#+ zmp+1bS!8W#Yg06pMXX|4JBh<$TV|aa2n;OqCXluW3i4jU=NTN?H}ADg=M}{15VS?u zrTYq@qeDaBOCBt-7H1Bgx?v2^7FC%r*Kv_2EHkuN;_7}vR;CgbppB?zxqui~Dt1~c zClTw@*}xlpv`B#s+JMeSwP{is2=7NS=W#4ZpF{6O3B4g^k)LD zs^E>E#3-qJ_uUpmY~u;eaw1W+!Z0w1BZH>Q!E$J6miDQkZJPWPdG5gYi`X-k&p%j* z5SE5OTYlu#{h3|&=S5y(V&dl<(nm9fCvA09S&#k}A4jbI{maFLXzy9rAFQS0*R6Ue z*X5f`K3?#v0@(yf^Sd6M9NPb7UAJ&(pNfzCWUdZ>;g|f8{zQ-LB53K6UFyML)T?Z= z@tgGIurC)sQKI3J=dX)#ZN*cTMyY6`W?fu}&)xbnp-v6|{mHk;=V!L=cd=D5J%a;r zIBxj$;$e51bwqr5;E@j(l;bz}?>}Drq%l+h>wAB&Rz}ca=@0sa$CHqXe;~9fl>Y4- zU`P00 zxzLJ!HMz)TH7fNh`;PB#s>yZu=Q&^hw(GwDoZmso0Nur300000NkvXXu0mjf@bL%9 literal 0 HcmV?d00001 diff --git a/doc/sane.tex b/doc/sane.tex new file mode 100644 index 0000000..726dc75 --- /dev/null +++ b/doc/sane.tex @@ -0,0 +1,1869 @@ +\documentclass[11pt,DVIps]{report} + +\usepackage{times,epsfig,changebar,html} + +\setlength{\parindent}{0pt} +\setlength{\parskip}{1.5ex plus 0.5ex minus 0.5ex} +\setlength{\textwidth}{6.5in} +\setlength{\textheight}{8.5in} +\setlength{\marginparwidth}{0pt} +\setlength{\oddsidemargin}{0pt} +\setlength{\evensidemargin}{0pt} +\setlength{\marginparsep}{0pt} +\addtolength{\topmargin}{-0.75in} + +\title{\huge SANE Standard Version 1.01} +\author{} +\date{October 17, 2000} + +\makeindex + +\begin{document} + +\newcommand{\filename}[1]{{\tt #1}} +\newcommand{\code}[1]{{\tt #1}} +\newcommand{\var}[1]{{\it #1}} +\newcommand{\defn}[1]{#1\index{#1}} + +\begin{latexonly} + \setcounter{changebargrey}{0} % black change bars +\end{latexonly} + +\maketitle +\tableofcontents +\listoffigures +\listoftables + + +\chapter{Preface} + +The SANE standard is being developed by a group of free-software +developers. The process is open to the public and comments as well as +suggestions for improvements are welcome. Information on how to join +the SANE development process can be found in Chapter +\ref{chap:contact}. + +The SANE standard is intended to streamline software development by +providing a standard application programming interface to access +raster scanner hardware. This should reduce the number of different +driver implementations, thereby reducing the need for reimplementing +similar code. + + +\section{About This Document} + +This document is intended for developers who are creating either an +application that requires access to raster scanner hardware and for +developers who are implementing a SANE driver. It does not cover +specific implementations of SANE components. Its sole purpose is to +describe and define the SANE application interface that will enable +any application on any platform to interoperate with any SANE backend +for that platform. + +The remainder of this document is organized as follows. +Chapter~\ref{chap:intro} provides introductional material. +Chapter~\ref{chap:environ} presents the environment SANE is designed +for. Chapter~\ref{chap:api} details the SANE Application Programmer +Interface. Chapter~\ref{chap:net} specifies the network protocol that +can be used to implement the SANE API in a network transparent +fashion. Finally, Chapter~\ref{chap:contact} gives information on how +to join the SANE development process. + +\subsection{Typographic Conventions} + +Changes since the last revision of this document are highlighted +like this: + +% \begin{changebar} +% Paragraphs that changed since the last revision of the documention +% are marked like this paragraph. +% \end{changebar} + +\chapter{Introduction}\label{chap:intro} + +SANE is an application programming interface (API) that provides +standardized access to any raster image scanner hardware. The +standardized interface allows to write just one driver for each +scanner device instead of one driver for each scanner and application. +The reduction in the number of required drivers provides significant +savings in development time. More importantly, SANE raises the level +at which applications can work. As such, it will enable applications +that were previously unheard of in the UNIX world. While SANE is +primarily targeted at a UNIX environment, the standard has been +carefully designed to make it possible to implement the API on +virtually any hardware or operating system. + +SANE is an acronym for ``Scanner Access Now Easy.'' Also, the hope is +that SANE is sane in the sense that it will allow easy implementation +of the API while accommodating all features required by today's +scanner hardware and applications. Specifically, SANE should be broad +enough to accommodate devices such as scanners, digital still and +video cameras, as well as virtual devices like image file filters. + +\section{Terminology} + +An application that uses the SANE interface is called a SANE {\em + frontend}. A driver that implements the SANE interface is called a +SANE {\em backend}. A {\em meta backend\/} provides some means to +manage one or more other backends. + + +\chapter{The SANE Environment}\label{chap:environ} + +SANE is defined as a C-callable library interface. Accessing a raster +scanner device typically consists of two phases: first, various +controls of the scanner need to be setup or queried. In the second +phase, one or more images are acquired. + +Since the device controls are widely different from device to device, +SANE provides a generic interface that makes it easy for a frontend to +give a user access to all controls without having to understand each +and every device control. The design principle used here is to +abstract each device control into a SANE {\em option\/}. An option is +a self-describing name/value pair. For example, the brightness +control of a camera might be represented by an option called +\code{brightness} whose value is an integer in the range from 0 to +255. + +With self-describing options, a backend need not be concerned with +{\em presentation\/} issues: the backend simply provides a list of +options that describe all the controls available in the device. +Similarly, there are benefits to the frontend: it need not be +concerned with the {\em meaning\/} of each option. It simply provides +means to present and alter the options defined by the backend. + + +\section{Attaching to a SANE backend} + +The process through which a SANE frontend connects to a backend is +platform dependent. Several possibilities exist: +\begin{itemize} + +\item {\bf Static linking:} A SANE backend may be linked directly into + a frontend. While the simplest method of attaching to a backend, it + is somewhat limited in functionality since the available devices is + limited to the ones for which support has been linked in when the + frontend was built. But even so static linking can be quite useful, + particularly when combined with a backend that can access scanners + via a network. Also, it is possible to support multiple backends + simultaneously by implementing a meta backend that manages several + backends that have been compiled in such a manner that they export + unique function names. For example, a backend called \code{be} + would normally export a function called \code{sane\_read()}. If + each backend would provide such a function, static linking would + fail due to multiple conflicting definitions of the same symbol. + This can be resolved by having backend \code{be} include a + header file that has lines of the form: + \begin{quote} +\begin{verbatim} +#define sane_read be_sane_read +\end{verbatim} + \end{quote} + With definitions of this kind, backend \code{be} will export + function name \code{be\_sane\_read()}. Thus, all backends will + export unique names. As long as a meta backend knows about these + names, it is possible to combine several backends at link time and + select and use them dynamically at runtime. + +\item {\bf Dynamic linking:} A simpler yet more powerful way to + support multiple backends is to exploit dynamic linking on platforms + that support it. In this case, a frontend is linked against a + shared library that implements any SANE backend. Since each + dynamically linked backend exports the same set of global symbols + (all starting with the prefix \code{sane\_}), the dynamic library + that gets loaded at runtime does not necessarily have to be the same + one as one the frontend got linked against. In other words, it is + possible to switch the backend by installing the appropriate backend + dynamic library. + + More importantly, dynamic linking makes it easy to implement a meta + backend that loads other backends {\em on demand}. This is a + powerful mechanism since it allows adding new backends merely by + installing a shared library and updating a configuration file. + +\item {\bf Network connection:} Arguably the ultimate way to attach to + a scanner is by using the network to connect to a backend on a + remote machine. This makes it possible to scan images from any host + in the universe, as long as there is a network connection to that + host and provided the user is permitted to access that scanner. + +\end{itemize} + +\begin{figure}[htbp] + \begin{center} + \leavevmode + \psfig{file=figs/hierarchy.eps,angle=270,width=\textwidth} + \caption{Example SANE Hiearchy} + \label{fig:hierarchy} + \end{center} +\end{figure} + +The above discussion lists just a few ways for frontends to attach to +a backend. It is of course possible to combine these solutions to +provide an entire hierarchy of SANE backends. Such a hierarchy is +depicted in Figure~\ref{fig:hierarchy}. The figure shows that machine +A uses a dynamic-linking based meta backend called \code{dll} to +access the backends called \code{pnm}, \code{mustek}, and \code{net}. +The first two are real backends, whereas the last one is a meta +backend that provides network transparent access to remote scanners. +In the figure, machine B provides non-local access to its scanners +through the SANE frontend called \code{saned}. The \code{saned} in +turn has access to the \code{hp} and \code{autolum} backends through +another instance of the \code{dll} backend. The \code{autolum} meta +backend is used to automatically adjust the luminance (brightness) of +the image data acquired by the camera backend called \code{qcam}. + +Note that a meta backend really is both a frontend and a backend at +the same time. It is a frontend from the viewpoint of the backends +that it manages and a backend from the viewpoint of the frontends that +access it. The name ``meta backend'' was chosen primarily because the +SANE standard describes the interface from the viewpoint of a (real) +frontend. + + +\section{Image Data Format}\label{sec:imageformat}\index{image data format} + +Arguably the most important aspect of an image acquisition system is +how images are represented. The SANE approach is to define a simple +yet powerful representation that is sufficient for vast majority of +applications and devices. While the representation is simple, the +interface has been defined carefully to allow extending it in the +future without breaking backwards compatibility. Thus, it will be +possible to accommodate future applications or devices that were not +anticipated at the time this standard was created. + +A SANE image is a rectangular area. The rectangular area is +subdivided into a number of rows and columns. At the intersection of +each row and column is a quadratic pixel. A pixel consists of one or +more sample values. Each sample value represents one channel (e.g., +the red channel). Each sample value has a certain bit depth. The bit +depth is fixed for the entire image and can be as small as one bit. +Valid bit depths are 1, 8, or 16 bits per sample. If a device's +natural bit depth is something else, it is up to the driver to scale +the sample values appropriately (e.g., a 4 bit sample could be scaled +by a factor of four to represent a sample value of depth 8). + +\subsection{Image Transmission} + +The SANE API transmits an image as a sequence of frames. Each frame +covers the same rectangular area as the entire image, but may contain +only a subset of the channels in the final image. For example, a +red/green/blue image could either be transmitted as a single frame +that contains the sample values for all three channels or it could be +transmitted as a sequence of three frames: the first frame containing +the red channel, the second the green channel, and the third the blue +channel. + +Conceptually, each frame is transmitted a byte at a time. Each byte +may contain 8 sample values (for an image bit depth of 1), one full +sample value (for an image bit depth of 8), or a partial sample value +(for an image bit depth of 16 or bigger). In the latter case, the +bytes of each sample value are transmitted in the machine's native +byte order. +\begin{quote} + \begin{center} + {\bf Backend Implementation Note} + \end{center} + A network-based meta backend will have to ensure that the byte order + in image data is adjusted appropriately if necessary. For example, + when the meta backend attaches to the server proxy, the proxy may + inform the backend of the server's byte order. The backend can then + apply the adjustment if necessary. In essence, this implements a + ``receiver-makes-right'' approach. +\end{quote} + +\begin{figure}[htbp] + \begin{center} + \leavevmode + \psfig{file=figs/xfer.eps,width=0.5\textwidth} + \caption{Transfer order of image data bytes} + \label{fig:xfer} + \end{center} +\end{figure} + +The order in which the sample values in a frame are transmitted is +illustrated in Figure~\ref{fig:xfer}. As can be seen, the values are +transmitted row by row and each row is transmitted from left-most to +right-most column. The left-to-right, top-to-bottom transmission +order applies when the image is viewed in its normal orientation (as +it would be displayed on a screen, for example). + +If a frame contains multiple channels, then the channels are +transmitted in an interleaved fashion. Figure~\ref{fig:pixels} +illustrates this for the case where a frame contains a complete +red/green/blue image with a bit-depth of 8. For a bit depth of 1, +each byte contains 8 sample values of a {\em single\/} channel. In +other words, a bit depth 1 frame is transmitted in a byte interleaved +fashion. + +\begin{figure}[htbp] + \begin{center} + \leavevmode + \psfig{file=figs/image-data.eps,width=0.8\textwidth} + \caption{Bit and byte order or image data} + \label{fig:pixels} + \end{center} +\end{figure} + +When transmitting an image frame by frame, the frontend needs to know +what part of the image a frame represents (and how many frames it +should expect). For that purpose, the SANE API tags every frame with +a type. This version of the SANE standard supports the following +frame types: +\begin{quote} +\begin{description} + +\item[\code{\defn{SANE\_FRAME\_GRAY}}:] The frame contains a single + channel of data that represents sample values from a spectral band + that covers the human visual range. The image consists of this + frame only. + +\item[\code{\defn{SANE\_FRAME\_RGB}}:] The frame contains three + channels of data that represent sample values from the red, green, + and blue spectral bands. The sample values are interleaved in the + order red, green, and blue. The image consists of this frame only. + +\item[\code{\defn{SANE\_FRAME\_RED}}:] The frame contains one channel + of data that represents sample values from the red spectral band. + The complete image consists of three frames: + \code{SANE\_\-FRA\-ME\_RED}, \code{SANE\_FRAME\_GREEN}, and + \code{SANE\_FRAME\_BLUE}. The order in which the frames are + transmitted chosen by the backend. + +\item[\code{\defn{SANE\_FRAME\_GREEN}}:] The frame contains one + channel of data that represents sample values from the green + spectral band. The complete image consists of three frames: + \code{SANE\_\-FRA\-ME\_RED}, \code{SANE\_FRAME\_GREEN}, and + \code{SANE\_FRAME\_BLUE}. The order in which the frames are + transmitted chosen by the backend. + +\item[\code{\defn{SANE\_FRAME\_BLUE}}:] The frame contains one channel + of data that represents sample values from the blue spectral band. + The complete image consists of three frames: + \code{SANE\_\-FRA\-ME\_RED}, \code{SANE\_FRAME\_GREEN}, and + \code{SANE\_FRAME\_BLUE}. The order in which the frames are + transmitted chosen by the backend. + +\end{description} +\end{quote} + +In frames of type SANE\_FRAME\_GRAY, when the bit depth is 1 there are +only two sample values possible, 1 represents minimum intensity +(black) and 0 represents maximum intensity (white). For all other bit +depth and frame type combinations, a sample value of 0 represents +minimum intensity and larger values represent increasing intensity. + + +\chapter{The SANE Application Programmer Interface (API)}\label{chap:api} + +This Section defines version 1 of the SANE application +programmer interface (API). Any SANE frontend must depend on the +interface defined in this section only. Converseley, any SANE backend +must implement its functionality in accordance with this +specification. The interface as documented here is declared as a C +callable interface in a file called \filename{sane/sane.h}. This file should +normally be included via a C pre-processor directive of the form: +\begin{verbatim} + #include +\end{verbatim} + + +\section{Version Control} + +The SANE standard is expected to evolve over time. Whenever a change +to the SANE standard is made that may render an existing frontend or +backend incompatible with the new standard, the major version number +must be increased. Thus, any frontend/backend pair is compatible +provided the major version number of the SANE standard they implement +is the same. A frontend may implement backwards compatiblity by +allowing major numbers that are smaller than the expected major number +(provided the frontend really can cope with the older version). In +contrast, a backend always provides support for one and only one +version of the standard. If a specific application does require that +two different versions of the same backend are accessible at the same +time, it is possible to do so by installing the two versions under +different names. + +SANE version control also includes a minor version number and a build +revision. While control of these numbers remains with the implementor +of a backend, the recommended use is as follows. The minor version is +incremented with each official release of a backend. The build +revision is increased with each build of a backend. + +The SANE API provides the following five macros to manage version +numbers. +\begin{quote} + \begin{description} + \item[\code{\defn{SANE\_CURRENT\_MAJOR}}:] The value of this macro is the + number of the SANE standard that the interface implements. + + \item[\code{\defn{SANE\_VERSION\_CODE}(\var{maj},\var{min},\var{bld})}:] + \label{sec:saneversioncode} + This macro can be used to build a monotonically increasing version + code. A SANE version code consists of the SANE standard major + version number (\var{maj}), the minor version number \var{min}, + and the build revision of a backend (\var{bld}). The major and + minor version numbers must be in the range 0\ldots255 and the + build revision must be in the range 0\ldots65535. + + Version codes are monotonic in the sense that it is possible to + apply relational operators (e.g., equality or less-than test) + directly on the version code rather than individually on the three + components of the version code. + + Note that the major version number alone determines whether a + frontend/backend pair is compatible. The minor version and the + build revision are used for informational and bug-fixing purposes + only. + + \item[\code{\defn{SANE\_VERSION\_MAJOR}(\var{vc})}:] This macro returns the + major version number component of the version code passed in + argument \var{vc}. + \item[\code{SANE\_VERSION\_MINOR(\var{vc})}:] This macro returns the + minor version number component of the version code passed in + argument \var{vc}. + \item[\code{SANE\_VERSION\_BUILD(\var{vc})}:] This macro returns the + build revision component of the version code passed in argument + \var{vc}. + \end{description} +\end{quote} + + +\section{Data Types} + +\subsection{Base Types} + +The SANE standard is based on just two SANE-specific base types: the +SANE byte and word. +\begin{quote} + \code{typedef \var{some-scalar-type\/} \defn{SANE\_Byte};} \\ + \code{typedef \var{some-scalar-type\/} \defn{SANE\_Word};} +\end{quote} +\verb|SANE_Byte| must correspond to some scalar C type that is capable +of holding values in the range 0 to 255. \verb|SANE_Word| must be +capable of holding any of the following: +\begin{itemize} + \item the truth values \verb|SANE_FALSE| and \verb|SANE_TRUE| + \item signed integers in the range $-2^{31}\ldots2^{31}-1$ + \item fixed point values in the range $-32768\ldots32767.9999$ with + a resolution of $1/65536$ + \item 32 bits (for bit sets) +\end{itemize} +Note that the SANE standard does not define what C type +\verb|SANE_Byte| and \verb|SANE_Word| map to. For example, on some +platforms, the latter may map to \verb|long int| whereas on others it +may map to \verb|int|. A portable SANE frontend or backend must +therefore not depend on a particular mapping. + +\subsection{Boolean Type} + +\code{\defn{SANE\_Bool}} is used for variables that can take one of +the two truth values \code{\defn{SANE\_FALSE}} and +\code{\defn{SANE\_TRUE}}. The former value is defined to be 0, +whereas the latter is 1.\footnote{This is different from ANSI C where + any non-zero integer value represents logical TRUE.} The C +declarations for this type are given below. +\begin{quote} +\begin{verbatim} +#define SANE_FALSE 0 +#define SANE_TRUE 1 +typedef SANE_Word SANE_Bool; +\end{verbatim} +\end{quote} +Note that \verb|SANE_Bool| is simply an alias of \verb|SANE_Word|. It +is therefore always legal to use the latter type in place of the +former. However, for clarity, it is recommended to use +\verb|SANE_Bool| whenever a given variable or formal argument has a +fixed interpretation as a boolean object. + +\subsection{Integer Type} + +\code{\defn{SANE\_Int}} is used for variables that can take integer +values in the range $-2^{32}$ to $2^{31}-1$. Its C declaration is +given below. +\begin{quote} +\begin{verbatim} +typedef SANE_Word SANE_Int; +\end{verbatim} +\end{quote} +Note that \verb|SANE_Int| is simply an alias of \verb|SANE_Word|. It +is therefore always legal to use the latter type in place of the +former. However, for clarity, it is recommended to use +\verb|SANE_Int| whenever a given variable or formal argument has a +fixed interpretation as an integer object. + + +\subsection{Fixed-point Type} + +\code{\defn{SANE\_Fixed}} is used for variables that can take fixed +point values in the range $-32768$ to $32767.9999$ with a resolution +of $1/65535$. The C declarations relating to this type are given +below. +\begin{quote} +\begin{verbatim} +#define SANE_FIXED_SCALE_SHIFT 16 +typedef SANE_Word SANE_Fixed; +\end{verbatim} +\end{quote} +The macro \code{\defn{SANE\_FIXED\_SCALE\_SHIFT}} gives the location +of the fixed binary point. This standard defines that value to be 16, +which yields a resolution of $1/65536$. + +Note that \verb|SANE_Fixed| is simply an alias of \verb|SANE_Word|. +It is therefore always legal to use the latter type in place of the +former. However, for clarity, it is recommended to use +\verb|SANE_Fixed| whenever a given variable or formal argument has a +fixed interpretation as a fixed-point object. + +For convenience, SANE also defines two macros that convert fixed-point +values to and from C double floating point values. +\begin{quote} + \begin{description} + + \item[\code{\defn{SANE\_FIX}(\var{d})}:] Returns the largest SANE + fixed-point value that is smaller than the double value \var{d}. + No range checking is performed. If the value of \var{d} is out of + range, the result is undefined. + + \item[\code{\defn{SANE\_UNFIX}(\var{w})}:] Returns the nearest + double machine number that corresponds to fixed-point value + \var{w}. + + \end{description} +\end{quote} +SANE does {\em not\/} require that the following two expressions hold +true (even if the values of \var{w} and \var{d} are in range): +\begin{quote} +\begin{verbatim} +SANE_UNFIX(SANE_FIX(d)) == d +SANE_FIX(SANE_UNFIX(w)) == w +\end{verbatim} +\end{quote} +In other words, conversion between fixed and double values may be +lossy. It is therefore recommended to avoid repeated conversions +between the two representations. + + +\subsection{Text} + +\subsubsection{Character Type} + +Type \code{\defn{SANE\_Char}} represents a single text character or +symbol. At present, this type maps directly to the underlying C +\verb|char| type (typically one byte). The encoding for such +characters is currently fixed as ISO LATIN-1. Future versions of this +standard may map this type to a wider type and allow multi-byte +encodings to support internationalization. As a result of this, care +should be taken to avoid the assumption that +\verb|sizeof(SANE\_Char)==sizeof(char)|. +\begin{quote} +\begin{verbatim} +typedef char SANE_Char; +\end{verbatim} +\end{quote} + +\subsubsection{String Type} + +Type \code{\defn{SANE\_String}} represents a text string as a sequence +of C \verb|char| values. The end of the sequence is indicated by a +\verb|'\0'| (\defn{NUL}) character. +\begin{quote} +\begin{verbatim} +typedef SANE_Char *SANE_String; +typedef const SANE_Char *SANE_String_Const; +\end{verbatim} +\end{quote} +The type \code{\defn{SANE\_String\_Const}} is provided by SANE to +enable declaring strings whose contents is unchangable. Note that in +ANSI C, the declaration +\begin{quote} +\begin{verbatim} +const SANE_String str; +\end{verbatim} +\end{quote} +declares a string pointer that is constant (not a string pointer that +points to a constant value). + + +\subsection{Scanner Handle Type} + +Access to a scanner is provided through an opaque type called +\code{\defn{SANE\_Handle}}. The C declaration of this type is given +below. +\begin{quote} +\begin{verbatim} +typedef void *SANE_Handle; +\end{verbatim} +\end{quote} +While this type is declared to be a void pointer, an application must +not attempt to interpret the value of a \verb|SANE_Handle|. In +particular, SANE does not require that a value of this type is a legal +pointer value. + + +\subsection{Status Type} + +Most SANE operations return a value of type \code{\defn{SANE\_Status}} +to indicate whether the completion status of the operation. If an +operation completes successfully, \verb|SANE_STATUS_GOOD| is returned. +In case of an error, a value is returned that indicates the nature of +the problem. The complete list of available status codes is listed in +Table \ref{tab:status}. It is recommended to use function +\code{sane\_strstatus()} to convert status codes into a legible +string. + +\begin{table}[htbp] + \begin{center} + \begin{tabular}{|l|r|l|} + \hline + \multicolumn{1}{|c|}{\bf Symbol} & \multicolumn{1}{c|}{\bf Code} & + \multicolumn{1}{c|}{\bf Description} \\ + \hline\hline +\code{\defn{SANE\_STATUS\_GOOD}} + & 0 & Operation completed succesfully. \\ +\code{\defn{SANE\_STATUS\_UNSUPPORTED}} + & 1 & Operation is not supported. \\ +\code{\defn{SANE\_STATUS\_CANCELLED}} + & 2 & Operation was cancelled. \\ +\code{\defn{SANE\_STATUS\_DEVICE\_BUSY}} + & 3 & Device is busy---retry later. \\ +\code{\defn{SANE\_STATUS\_INVAL}} + & 4 & Data or argument is invalid. \\ +\code{\defn{SANE\_STATUS\_EOF}} + & 5 & No more data available (end-of-file). \\ +\code{\defn{SANE\_STATUS\_JAMMED}} + & 6 & Document feeder jammed. \\ +\code{\defn{SANE\_STATUS\_NO\_DOCS}} + & 7 & Document feeder out of documents. \\ +\code{\defn{SANE\_STATUS\_COVER\_OPEN}} + & 8 & Scanner cover is open. \\ +\code{\defn{SANE\_STATUS\_IO\_ERROR}} + & 9 & Error during device I/O. \\ +\code{\defn{SANE\_STATUS\_NO\_MEM}} + & 10 & Out of memory. \\ +\code{\defn{SANE\_STATUS\_ACCESS\_DENIED}} + & 11 & Access to resource has been denied. \\ + \hline + \end{tabular} + \caption{Status Codes}\label{tab:status} + \end{center} +\end{table} + + +\subsection{Device Descriptor Type} + +Each SANE device is represented by a structure of type +\code{\defn{SANE\_Device}}. The C declaration of this type is given +below. +\begin{quote} +\begin{verbatim} +typedef struct + { + SANE_String_Const name; + SANE_String_Const vendor; + SANE_String_Const model; + SANE_String_Const type; + } +SANE_Device; +\end{verbatim} +\end{quote} +\index{device-name} +The structure provides the unique name of the scanner in member +\code{name}. It is this unique name that should be passed in a call +to \code{sane\_open()}. The format of this name is completely up to +the backend. The only constraints are that the name is unique among +all devices supported by the backend and that the name is a legal SANE +text string. To simplify presentation of unique names, their length +should not be excessive. It is {\em recommended\/} that backends keep +unique names below 32 characters in length. However, applications +{\em must\/} be able to cope with arbitrary length unique names. + +The remaining members in the device structure provide additional +information on the device corresponding to the unique name. +Specifically, members \code{vendor}, \code{model}, and \code{type} are +single-line strings that give information on the vendor +(manufacturer), model, and the type of the device. For consistency's +sake, the following strings should be used when appropriate (the lists +will be expanded as need arises): + +\begin{table}[htbp] + \begin{center} + \leavevmode + \hspace{\fill} + \begin{tabular}[t]{|ll|} + \hline + \multicolumn{2}{|c|}{\bf \defn{Vendor Strings}} \\ + \hline\hline + \code{AGFA} & \code{Logitech} \\ + \code{Artec} & \code{Microtek} \\ + \code{Connectix} & \code{Minolta} \\ + \code{Epson} & \code{Mustek} \\ + \code{Hewlett-Packard} & \code{UMAX} \\ + \code{Kodak} & \code{Noname} \\ + \hline + \end{tabular} + \hspace{\fill} + \begin{tabular}[t]{|l|} + \hline + \multicolumn{1}{|c|}{\bf \defn{Type Strings}} \\ + \hline\hline + \code{flatbed scanner} \\ + \code{frame grabber} \\ + \code{handheld scanner} \\ + \code{still camera} \\ + \code{video camera} \\ + \code{virtual device} \\ + \hline + \end{tabular} + \hspace{\fill} + \caption{Predefined Device Information Strings} + \label{tab:devinfo} + \end{center} +\end{table} +Note that vendor string \code{Noname} can be used for virtual devices +that have no physical vendor associated. Also, there are no +predefined model name strings since those are vendor specific and +therefore completely under control of the respective backends. + + +\subsection{Option Descriptor Type}\label{sec:odesc} + +Option descriptors are at the same time the most intricate and +powerful type in the SANE standard. Options are used to control +virtually all aspects of device operation. Much of the power of the +SANE API stems from the fact that most device controls are completely +described by their respective option descriptor. Thus, a frontend can +control a scanner abstractly, without requiring knowledge as to what +the purpose of any given option is. Conversely, a scanner can +describe its controls without requiring knowledge of how the frontend +operates. The C declaration of the +\code{\defn{SANE\_Option\_Descriptor}} type is given below. +\begin{quote} +\begin{verbatim} +typedef struct + { + SANE_String_Const name; + SANE_String_Const title; + SANE_String_Const desc; + SANE_Value_Type type; + SANE_Unit unit; + SANE_Int size; + SANE_Int cap; + SANE_Constraint_Type constraint_type; + union + { + const SANE_String_Const *string_list; + const SANE_Word *word_list; + const SANE_Range *range; + } + constraint; + } +SANE_Option_Descriptor; +\end{verbatim} +\end{quote} + +\subsubsection{Option Name} + +Member \code{name} is a string that uniquely identifies the option. +The name must be unique for a given device (i.e., the option names +across different backends or devices need not be unique). The option +name must consist of lower-case ASCII letters (\code{a}--\code{z}), +digits (\code{0}--\code{9}), or the dash character (\code{-}) only. +The first character must be a lower-case ASCII character (i.e., not a +digit or a dash). + +\subsubsection{Option Title} + +Member \code{title} is a single-line string that can be used by the +frontend as a title string. This should typically be a short (one or +two-word) string that is chosen based on the function of the option. + +\subsubsection{Option Description} + +Member \code{desc} is a (potentially very) long string that can be +used as a help text to describe the option. It is the responsibility +of the frontend to break the string into managable-length lines. +Newline characters in this string should be interpreted as paragraph +breaks. + +\subsubsection{Option Value Type} + +Member \code{type} specifies the type of the option value. The +possible values for type \code{\defn{SANE\_Value\_Type}} are described +in Table \ref{tab:valuetype}. + +\begin{table}[htbp] + \begin{center} + \leavevmode + \begin{tabular}{|l|l|p{0.6\textwidth}|} +\hline +\multicolumn{1}{|c|}{\bf Symbol} & +\multicolumn{1}{c|}{\bf Code} & +\multicolumn{1}{c|}{\bf Description} \\ +\hline\hline + +\code{\defn{SANE\_TYPE\_BOOL}} & 0 & Option value is of type + \verb|SANE_Bool|. \\ + +\code{\defn{SANE\_TYPE\_INT}} & 1 & Option value is of type + \verb|SANE_Int|. \\ + +\code{\defn{SANE\_TYPE\_FIXED}}&2 & Option value is of type + \verb|SANE_Fixed|. \\ + +\code{\defn{SANE\_TYPE\_STRING}}&3 & Option value is of type + \verb|SANE_String|. \\ + +\code{\defn{SANE\_TYPE\_BUTTON}} & 4 & An option of this type has no value. +Instead, setting an option of this type has an option-specific +side-effect. For example, a button-typed option could be used by a +backend to provide a means to select default values or to the tell an +automatic document feeder to advance to the next sheet of paper. \\ + +\code{\defn{SANE\_TYPE\_GROUP}} & 5 & An option of this type has no value. +This type is used to group logically related options. A group option +is in effect up to the point where another group option is encountered +(or up to the end of the option list, if there are no other group +options). For group options, only members \code{title} and +\code{type} are valid in the option descriptor. \\ + + \hline + \end{tabular} + \caption{Option Value Types (\code{SANE\_Value\_Type})} + \label{tab:valuetype} + \end{center} +\end{table} + +\subsubsection{Option Value Unit} + +Member \code{unit} specifies what the physical unit of the option +value is. The possible values for type \code{\defn{SANE\_U\-nit}} are +described in Table \ref{tab:units}. Note that the specified unit is +what the SANE backend expects. It is entirely up to a frontend as to +how these units a presented to the user. For example, SANE expresses +all lengths in millimeters. A frontend is generally expected to +provide appropriate conversion routines so that a user can express +quantities in a customary unit (e.g., inches or centimeters). + +\begin{table}[htbp] + \begin{center} + \leavevmode + \begin{tabular}{|l|l|l|} +\hline +\multicolumn{1}{|c|}{\bf Symbol} & +\multicolumn{1}{|c|}{\bf Code} & +\multicolumn{1}{|c|}{\bf Description} \\ + +\hline\hline + +\code{\defn{SANE\_UNIT\_NONE}} & 0 & Value is unit-less (e.g., page count).\\ +\code{\defn{SANE\_UNIT\_PIXEL}} & 1 & Value is in number of pixels. \\ +\code{\defn{SANE\_UNIT\_BIT}} & 2 & Value is in number of bits. \\ +\code{\defn{SANE\_UNIT\_MM}} & 3 & Value is in millimeters. \\ +\code{\defn{SANE\_UNIT\_DPI}} & 4 & Value is a resolution in dots/inch. \\ +\code{\defn{SANE\_UNIT\_PERCENT}}& 5 & Value is a percentage. \\ +\code{\defn{SANE\_UNIT\_MICROSECOND}}& 6 & Value is time in $\mu$-seconds. \\ + +\hline + \end{tabular} + \caption{Physical Units (\code{SANE\_Unit})} + \label{tab:units} + \end{center} +\end{table} + +\subsubsection{Option Value Size}\label{sec:valuesize} + +Member \code{size} specifies the size of the option value (in bytes). +This member has a slightly different interpretation depending on the +type of the option value: +\begin{quote} + \begin{description} + \item[\code{SANE\_TYPE\_STRING}:] The size is the maximum size of + the string. For the purpose of string size calcuations, the + terminating \code{NUL} character is considered to be part of the + string. Note that the terminating \code{NUL} character must + always be present in string option values. + \item[\code{SANE\_TYPE\_INT}, \code{SANE\_TYPE\_FIXED}:] The size + must be a positive integer multiple of the size of a + \verb|SANE_Word|. The option value is a vector of length + \[ \code{size}/\code{sizeof(SANE\_Word)}. \] + \item[\code{SANE\_TYPE\_BOOL}:] The size must be set to + \code{sizeof(SANE\_Word)}. + \item[\code{SANE\_TYPE\_BUTTON}, \code{SANE\_TYPE\_GROUP}:] The + option size is ignored. + \end{description} +\end{quote} + +\subsubsection{Option Capabilities} + +Member \code{cap} describes what capabilities the option posseses. +This is a bitset that is formed as the inclusive logical OR of the +capabilities described in Table \ref{tab:capabilities}. The SANE API +provides the following to macros to test certain features of a given +capability bitset: +\begin{quote} + \begin{description} + + \item[\code{\defn{SANE\_OPTION\_IS\_ACTIVE}(\var{cap})}:] This macro + returns \code{SANE\_TRUE} if and only if the option with the + capability set \var{cap} is currently active. + + \item[\code{\defn{SANE\_OPTION\_IS\_SETTABLE}(\var{cap})}:] This + macro returns \code{SANE\_TRUE} if and only if the option with the + capability set \var{cap} is software settable. + \end{description} +\end{quote} + +\begin{table}[htbp] + \begin{center} + \leavevmode + \begin{tabular}{|l|r|p{0.59\textwidth}|} +\hline +\multicolumn{1}{|c|}{\bf Symbol} & +\multicolumn{1}{c|}{\bf Code} & +\multicolumn{1}{c|}{\bf Description} \\ +\hline\hline + +\code{\defn{SANE\_CAP\_SOFT\_SELECT}} & 1 & The option + value can be set by a call to \code{sane\_con\-trol\_opt\-ion()}.\\ + +\code{\defn{SANE\_CAP\_HARD\_SELECT}} & 2 & The option value can be set by + user-intervention (e.g., by flipping a switch). The user-interface + should prompt the user to execute the appropriate action to set such + an option. This capability is mutually exclusive with + SANE\_CAP\_SOFT\_SELECT (either one of them can be set, but not both + simultaneously). \\ + +\code{\defn{SANE\_CAP\_SOFT\_DETECT}} & 4 & The option + value can be detected by software. If + \code{SANE\_\-CAP\_\-SO\-FT\_SEL\-ECT} is set, this capability {\em must\/} + be set. If \code{SANE\_CAP\_HARD\_SELECT} is set, this capability + may or may not be set. If this capability is set but neither + \code{SANE\_CAP\_SO\-FT\_SEL\-ECT} nor \code{SANE\_CAP\_HA\-RD\_SEL\-ECT} + are, then there is no way to control the option. That is, the + option provides read-out of the current value only. \\ + +\code{\defn{SANE\_CAP\_EMULATED}} & 8 & If set, this capability indicates + that an option is not directly supported by the device and is + instead emulated in the backend. A sophisticated frontend may + elect to use its own (presumably better) emulation in lieu of an emulated + option. \\ + +\code{\defn{SANE\_CAP\_AUTOMATIC}} & 16 & If set, this capability indicates + that the backend (or the device) is capable to picking a reasonable + option value automatically. For such options, it is possible to + select automatic operation by calling \code{sane\_control\_option()} + with an action value of \code{SANE\_ACTION\_SET\_AUTO}. \\ + +\code{\defn{SANE\_CAP\_INACTIVE}} & 32 & If set, this capability indicates + that the option is not currently active (e.g., because it's + meaningful only if another option is set to some other value). \\ + +\code{\defn{SANE\_CAP\_ADVANCED}} & 64 & + If set, this capability indicates that the option should be + considered an ``advanced user option.'' A frontend typically + displays such options in a less conspicuous way than regular options + (e.g., a command line interface may list such options last or a + graphical interface may make them available in a seperate ``advanced + settings'' dialog). + \\ + +\hline + \end{tabular} + \caption{Option Capabilities} + \label{tab:capabilities} + \end{center} +\end{table} + +\subsubsection{Option Value Constraints} + +It is often useful to constrain the values that an option can take. +For example, constraints can be used by a frontend to determine how to +represent a given option. Member \code{constraint\_type} indicates +what constraint is in effect for the option. The constrained values +that are allowed for the option are described by one of the union +members of member \code{constraint}. The possible values of type +\code{\defn{SANE\_Constraint\_Type}} and the interpretation of the +\code{constraint} union is described in Table~\ref{tab:constraints}. + +\begin{table}[htbp] + \begin{center} + \leavevmode + \begin{tabular}{|l|r|p{0.5\textwidth}|} +\hline +\multicolumn{1}{|c|}{\bf Symbol} & +\multicolumn{1}{|c|}{\bf Code} & +\multicolumn{1}{|c|}{\bf Description} \\ + +\hline\hline + +\code{\defn{SANE\_CONSTRAINT\_NONE}} & 0 & The value is unconstrained. + The option can take any of the values possible for the option's + type. \\ + + \code{\defn{SANE\_CONSTRAINT\_RANGE}} & 1 & This constraint is + applicable to integer and fixed-point valued options only. It + constrains the option value to a possibly quantized range of + numbers. Option descriptor member \code{constraint.range} points to + a range of the type \code{\defn{SANE\_Range}}. This type is illustrated + below: + \begin{quote} +\begin{verbatim} +typedef struct + { + SANE_Word min; + SANE_Word max; + SANE_Word quant; + } +SANE_Range; +\end{verbatim} + \end{quote} + All three members in this structure are interpreted according to the + option value type (\verb|SANE_TYPE_INT| or \verb|SANE_TYPE_FIXED|). + Members \code{min} and \code{max} specify the minimum and maximum + values, respectively. If member \code{quant} is non-zero, it + specifies the quantization value. If $l$ is the minimum value, $u$ + the maximum value and $q$ the (non-zero) quantization of a range, + then the legal values are $v=k\cdot q+l$ for all non-negative + integer values of $k$ such that $v<=u$. \\ + +\code{\defn{SANE\_CONSTRAINT\_WORD\_LIST}} & 2 & This constraint is applicable + to integer and fixed-point valued options only. It constrains the + option value to a list of numeric values. Option descriptor member + \code{constraint.word\_list} points to a list of words that + enumerates the legal values. The first element in that list is an + integer (\verb|SANE_Int|) that specifies the length of the list (not + counting the length itself). The remaining elements in the list are + interpreted according to the type of the option value + (\verb|SANE_TYPE_INT| or \verb|SANE_TYPE_FIXED|). \\ + +\code{\defn{SANE\_CONSTRAINT\_STRING\_LIST}} & 3 & This constraint is + applicable to string-valued options only. It constrains the option + value to a list of strings. The option descriptor member + \code{con\-strai\-nt.str\-ing\_list} points to a \code{NULL} terminated + list of strings that enumerate the legal values for the option + value. +\\\hline + \end{tabular} + \caption{Option Value Constraints} + \label{tab:constraints} + \end{center} +\end{table} + + +\section{Operations} + +\subsection{\code{sane\_init}} + +This function must be called before any other SANE function can be +called. The behavior of a SANE backend is undefined if this function +is not called first. The version code of the backend is returned in +the value pointed to by \code{version\_code}. If that pointer is +\code{NULL}, no version code is returned. + Argument \code{authorize} is either a pointer to a function that is + invoked when the backend requires authentication for a specific + resource or \code{NULL} if the frontend does not support + authentication. +\begin{quote}\index{sane\_init} +\begin{verbatim} +SANE_Status sane_init (SANE_Int * version_code, + SANE_Authorization_Callback authorize); +\end{verbatim} +\end{quote} + +The authorization function may be called by a backend in response to +any of the following calls: +\begin{quote} + \code{sane\_open}, \code{sane\_control\_option}, \code{sane\_start} +\end{quote} +If a backend was initialized without authorization function, then +authorization requests that cannot be handled by the backend itself +will fail automatically and the user may be prevented from accessing +protected resources. Backends are encouraged to implement means of +authentication that do not require user assistance. E.g., on a +multi-user system that authenticates users through a login process a +backend could automatically lookup the apporpriate password based on +resource- and user-name. + +The authentication function type has the following declaration: +\begin{quote}\index{SANE\_Authorization\_Callback} + \index{domain}\index{username}\index{password} +\begin{verbatim} +#define SANE_MAX_USERNAME_LEN 256 +#define SANE_MAX_PASSWORD_LEN 256 + +typedef void (*SANE_Authorization_Callback) + (SANE_String_Const resource, + SANE_Char username[SANE_MAX_USERNAME_LEN], + SANE_Char password[SANE_MAX_PASSWORD_LEN]); +\end{verbatim} +\end{quote} +Three arguments are passed to the authorization function: +\code{resource} is a string specifying the name of the resource that +requires authorization. A frontend should use this string to build a +user-prompt requesting a username and a password. The \code{username} +and \code{password} arguments are (pointers to) an array of +\code{SANE\_MAX\_USERNAME\_LEN} and \code{SANE\_MAX\_PASSWORD\_LEN} +characters, respectively. The authorization call should place the +entered username and password in these arrays. The returned strings +{\em must\/} be ASCII-NUL terminated. + +\subsection{\code{sane\_exit}} + +This function must be called to terminate use of a backend. The +function will first close all device handles that still might be open +(it is recommended to close device handles explicitly through a call +to \code{sane\_clo\-se()}, but backends are required to release all +resources upon a call to this function). After this function returns, +no function other than \code{sane\_init()} may be called (regardless +of the status value returned by \code{sane\_exit()}. Neglecting to +call this function may result in some resources not being released +properly. +\begin{quote}\index{sane\_exit} +\begin{verbatim} +void sane_exit (void); +\end{verbatim} +\end{quote} + + +\subsection{\code{sane\_get\_devices}} + +This function can be used to query the list of devices that are +available. If the function executes successfully, it stores a pointer +to a \code{NULL} terminated array of pointers to \verb|SANE_Device| +structures in \code{*device\_list}. The returned list is guaranteed +to remain unchanged and valid until (a) another call to this function +is performed or (b) a call to \code{sane\_exit()} is performed. This +function can be called repeatedly to detect when new devices become +available. If argument \code{local\_only} is true, only local devices +are returned (devices directly attached to the machine that SANE is +running on). If it is false, the device list includes all remote +devices that are accessible to the SANE library. +\begin{quote}\index{sane\_get\_devices} +\begin{verbatim} +SANE_Status sane_get_devices (const SANE_Device *** device_list, + SANE_Bool local_only); +\end{verbatim} +\end{quote} + +This function may fail with \code{SANE\_STATUS\_NO\_MEM} if an +insufficient amount of memory is available. + +\begin{quote} + \begin{center} + {\bf Backend Implementation Note} + \end{center} + SANE does not require that this function is called before a + \code{sane\_open()} call is performed. A device name may be + specified explicitly by a user which would make it unnecessary and + undesirable to call this function first. +\end{quote} + + +\subsection{\code{sane\_open}} + +This function is used to establish a connection to a particular +device. The name of the device to be opened is passed in argument +\code{name}. If the call completes successfully, a handle for the +device is returned in \code{*h}. As a special case, specifying a +zero-length string as the device requests opening the first available +device (if there is such a device). +\begin{quote}\index{sane\_open} +\begin{verbatim} +SANE_Status sane_open (SANE_String_Const name, SANE_Handle * h); +\end{verbatim} +\end{quote} + +This function may fail with one of the following status codes. +\begin{quote} +\begin{description} +\item[\code{SANE\_STATUS\_DEVICE\_BUSY}:] The device is currently + busy (in use by somebody else). +\item[\code{SANE\_STATUS\_INVAL}:] The device name is not valid. +\item[\code{SANE\_STATUS\_IO\_ERROR}:] An error occured while + communicating with the device. +\item[\code{SANE\_STATUS\_NO\_MEM}:] An insufficent amount of memory + is available. +\item[\code{SANE\_STATUS\_ACCESS\_DENIED}:] Access to the device has + been denied due to insufficient or invalid authentication. +\end{description} +\end{quote} + + +\subsection{\code{sane\_close}} + +This function terminates the association between the device handle +passed in argument \code{h} and the device it represents. If the +device is presently active, a call to \code{sane\_cancel()} is +performed first. After this function returns, handle \code{h} must +not be used anymore. + +\begin{quote}\index{sane\_close} +\begin{verbatim} +void sane_close (SANE_Handle h); +\end{verbatim} +\end{quote} + +\subsection{\code{sane\_get\_option\_descriptor}} + +This function is used to access option descriptors. The function +returns the option descriptor for option number \code{n} of the device +represented by handle \code{h}. Option number 0 is guaranteed to be a +valid option. Its value is an integer that specifies the number of +options that are available for device handle \code{h} (the count +includes option 0). If $n$ is not a valid option index, the function +returns \code{NULL}. The returned option descriptor is guaranteed to +remain valid (and at the returned address) until the device is closed. + +\begin{quote}\index{sane\_get\_option\_descriptor} +\begin{verbatim} +const SANE_Option_Descriptor * + sane_get_option_descriptor (SANE_Handle h, SANE_Int n); +\end{verbatim} +\end{quote} + +\subsection{\code{sane\_control\_option}}\label{sec:control} + +This function is used to set or inquire the current value of option +number \code{n} of the device represented by handle \code{h}. The +manner in which the option is controlled is specified by parameter +\code{a}. The possible values of this parameter are described in more +detail below. The value of the option is passed through argument +\code{v}. It is a pointer to the memory that holds the option value. +The memory area pointed to by \code{v} must be big enough to hold the +entire option value (determined by member \code{size} in the +corresponding option descriptor). The only exception to this rule is +that when setting the value of a string option, the string pointed to +by argument \code{v} may be shorter since the backend will stop +reading the option value upon encountering the first \code{NUL} +terminator in the string. If argument \code{i} is not \code{NULL}, +the value of \code{*i} will be set to provide details on how well the +request has been met. The meaning of this argument is described in +more detail below. +\begin{quote}\index{sane\_control\_option} +\begin{verbatim} +SANE_Status sane_control_option (SANE_Handle h, SANE_Int n, + SANE_Action a, void *v, + SANE_Int * i); +\end{verbatim} +\end{quote} + +The way the option is affected by a call to this function is +controlled by parameter \code{a} which is a value of type +\code{\defn{SANE\_Action}}. The possible values and their meaning is +described in Table~\ref{tab:actions}. + +\begin{table}[h] + \begin{center} + \leavevmode + \begin{tabular}{|l|r|p{0.5\textwidth}|} +\hline +\multicolumn{1}{|c|}{\bf Symbol} & +\multicolumn{1}{|c|}{\bf Code} & +\multicolumn{1}{|c|}{\bf Description} \\ + +\hline\hline + +\code{\defn{SANE\_ACTION\_GET\_VALUE}} & 0 & Get current option value. \\ + +\code{\defn{SANE\_ACTION\_SET\_VALUE}} & 1 & Set option value. The + option value passed through argument \code{v} may be modified by the + backend if the value cannot be set exactly. \\ + +\code{\defn{SANE\_ACTION\_SET\_AUTO}} & 2 & Turn on automatic mode. Backend + or device will automatically select an appropriate value. This mode + remains effective until overridden by an explicit set value request. + The value of parameter \code{v} is completely ignored in this case and + may be \code{NULL}. \\ + +\hline + \end{tabular} + \caption{Action Values (\code{SANE\_Action})} + \label{tab:actions} + \end{center} +\end{table} + +After setting a value via an action value of +\verb|SANE_ACTION_SET_VALUE|, additional information on how well the +request has been met is returned in \code{*i} (if \code{i} is +non-\code{NULL}). The returned value is a bitset that may contain any +combination of the values described in Table~\ref{tab:info}. +\begin{table}[htbp] + \begin{center} + \leavevmode + \begin{tabular}{|l|r|p{0.5\textwidth}|} +\hline +\multicolumn{1}{|c|}{\bf Symbol} & +\multicolumn{1}{|c|}{\bf Code} & +\multicolumn{1}{|c|}{\bf Description} \\ + +\hline\hline + +\code{\defn{SANE\_INFO\_INEXACT}} & 1 & This value is returned when + setting an option value resulted in a value being selected that does + not exactly match the requested value. For example, if a scanner + can adjust the resolution in increments of 30dpi only, setting the + resolution to 307dpi may result in an actual setting of 300dpi. + When this happens, the bitset returned in \code{*i} has this member + set. In addition, the option value is modified to reflect the + actual (rounded) value that was used by the backend. Note that + inexact values are admissible for strings as well. A backend may + choose to ``round'' a string to the closest matching legal string + for a constrained string value. \\ + + \code{\defn{SANE\_INFO\_RELOAD\_OPTIONS}} & 2 & The setting of an + option may affect the value or availability of one or more {\em + other\/} options. When this happens, the SANE backend sets this + member in \code{*i} to indicate that the application should reload + all options. This member may be set if and only if at least one + option changed. \\ + +\code{\defn{SANE\_INFO\_RELOAD\_PARAMS}} & 4 & The setting of an option may + affect the parameter values (see \code{sane\_get\_parameters()}). + If setting an option affects the parameter values, this member will + be set in \code{*i}. Note that this member may be set even if the + parameters did not actually change. However, it is guaranteed that + the parameters never change without this member being set. \\ + +\hline + \end{tabular} + \caption{Additional Information Returned When Setting an Option} + \label{tab:info} + \end{center} +\end{table} + +This function may fail with one of the following status codes. +\begin{quote} +\begin{description} +\item[\code{SANE\_STATUS\_UNSUPPORTED}:] The operation is not + supported for the specified handle and option number. +\item[\code{SANE\_STATUS\_INVAL}:] The option value is not valid. +\item[\code{SANE\_STATUS\_IO\_ERROR}:] An error occured while + communicating with the device. +\item[\code{SANE\_STATUS\_NO\_MEM}:] An insufficent amount of memory + is available. +\item[\code{SANE\_STATUS\_ACCESS\_DENIED}:] Access to the option has + been denied due to insufficient or invalid authentication. +\end{description} +\end{quote} + + + +\subsection{\code{sane\_get\_parameters}} + +This function is used to obtain the current scan parameters. The +returned parameters are guaranteed to be accurate between the time a +scan has been started (\code{sane\_start()} has been called) and the +completion of that request. Outside of that window, the returned +values are best-effort estimates of what the parameters will be when +\code{sane\_start()} gets invoked. Calling this function before a +scan has actually started allows, for example, to get an estimate of +how big the scanned image will be. The parameters passed to this +function are the handle \code{h} of the device for which the +parameters should be obtained and a pointer \code{p} to a parameter +structure. The parameter structure is described in more detail below. + +\begin{quote}\index{sane\_get\_parameters} +\begin{verbatim} +SANE_Status sane_get_parameters (SANE_Handle h, + SANE_Parameters * p); +\end{verbatim} +\end{quote} + +The scan parameters are returned in a structure of type +\code{\defn{SANE\_Parameters}}. The C declaration of this structure +is given below. +\begin{quote} +\begin{verbatim} +typedef struct + { + SANE_Frame format; + SANE_Bool last_frame; + SANE_Int lines; + SANE_Int depth; + SANE_Int pixels_per_line; + SANE_Int bytes_per_line; + } +SANE_Parameters; +\end{verbatim} +\end{quote} + +Member \code{format} specifies the format of the next frame to be +returned. The possible values for type \code{\defn{SANE\_Frame}} are +described in Table~\ref{tab:frameformat}. The meaning of these +values is described in more detail in Section~\ref{sec:imageformat}. +\begin{table}[htbp] + \begin{center} + \leavevmode + \begin{tabular}{|l|r|l|} +\hline +\multicolumn{1}{|c|}{\bf Symbol} & +\multicolumn{1}{|c|}{\bf Code} & +\multicolumn{1}{|c|}{\bf Description} \\ + +\hline\hline + +\code{\defn{SANE\_FRAME\_GRAY}} & 0 & Band covering human visual range. \\ +\code{\defn{SANE\_FRAME\_RGB}} & 1 & Pixel-interleaved red/green/blue bands. \\ +\code{\defn{SANE\_FRAME\_RED}} & 2 & Red band of a red/green/blue image. \\ +\code{\defn{SANE\_FRAME\_GREEN}} & 3 & Green band of a red/green/blue image. \\ +\code{\defn{SANE\_FRAME\_BLUE}} & 4 & Blue band of a red/green/blue image. \\ + +\hline + \end{tabular} + \caption{Frame Format (\code{SANE\_Frame})} + \label{tab:frameformat} + \end{center} +\end{table} + +Member \code{last\_frame} is set to \code{SANE\_TRUE} if and only if +the frame that is currently being acquired (or the frame that will be +acquired next if there is no current frame) is the last frame of a +multi frame image (e.g., the current frame is the blue component of a +red, green, blue image). + +Member \code{lines} specifies how many scan lines the frame is +comprised of. If this value is -1, the number of lines is not known a +priori and the frontend should call \code{sane\_read()} until it +returns a status of \code{SANE\_STATUS\_EOF}. + +Member \code{bytes\_per\_line} specifies the number of bytes that +comprise one scan line. + +Member \code{depth} specifies the number of bits per sample. + +Member \code{pixels\_per\_line} specifies the number of pixels that +comprise one scan line. + +Assume $B$ is the number of channels in the frame, then the bit depth +$d$ (as given by member \code{depth}) and the number of pixels per +line $n$ (as given by this member \code{pixels\_per\_line}) are +related to $c$, the number of bytes per line (as given by member +\code{bytes\_per\_line}) as follows: +\[ + c >= \left\{ + \begin{array}{ll} + \lceil B\cdot n / 8\rceil & \mbox{if $d=1$}\\ + B\cdot n \cdot \lceil (d + 7)/8 \rceil & \mbox{if $d>1$} + \end{array} + \right. +\] +Note that the number of bytes per line can be larger than the minimum +value imposed by the right side of this equation. A frontend must be +able to properly cope with such ``padded'' image formats. + + +\subsection{\code{sane\_start}} + +This function initiates aquisition of an image from the device +represented by handle \code{h}. +\begin{quote}\index{sane\_start} +\begin{verbatim} +SANE_Status sane_start (SANE_Handle h); +\end{verbatim} +\end{quote} +This function may fail with one of the following status codes. +\begin{quote} +\begin{description} +\item[\code{SANE\_STATUS\_CANCELLED}:] The operation was cancelled through + a call to \code{sane\_cancel}. +\item[\code{SANE\_STATUS\_DEVICE\_BUSY}:] The device is busy. The + operation should be retried later. +\item[\code{SANE\_STATUS\_JAMMED}:] The document feeder is jammed. +\item[\code{SANE\_STATUS\_NO\_DOCS}:] The document feeder is out of + documents. +\item[\code{SANE\_STATUS\_COVER\_OPEN}:] The scanner cover is open. +\item[\code{SANE\_STATUS\_IO\_ERROR}:] An error occurred while communicating + with the device. +\item[\code{SANE\_STATUS\_NO\_MEM}:] An insufficent amount of memory + is available. +\end{description} +\end{quote} + + +\subsection{\code{sane\_read}} + +This function is used to read image data from the device represented +by handle \code{h}. Argument \code{buf} is a pointer to a memory area +that is at least \code{maxlen} bytes long. The number of bytes +returned is stored in \code{*len}. A backend must set this to zero +when the call fails (i.e., when a status other than +\code{SANE\_STA\-TUS\_GOOD} is returned). When the call succeeds, the +number of bytes returned can be anywhere in the range from 0 to +\code{maxlen} bytes. +\begin{quote}\index{sane\_read} +\begin{verbatim} +SANE_Status sane_read (SANE_Handle h, SANE_Byte * buf, + SANE_Int maxlen, SANE_Int * len); +\end{verbatim} +\end{quote} +If this function is called when no data is available, one of two +things may happen, depending on the I/O mode that is in effect for +handle \code{h}. +\begin{enumerate} +\item If the device is in blocking I/O mode (the default mode), the + call blocks until at least one data byte is available (or until some + error occurs). + +\item If the device is in non-blocking I/O mode, the call returns + immediately with status \code{SANE\_STA\-TUS\_GOOD} and with + \code{*len} set to zero. +\end{enumerate} +The I/O mode of handle \code{h} can be set via a call to +\code{sane\_set\_io\_mode()}. + +This function may fail with one of the following status codes. +\begin{quote} +\begin{description} +\item[\code{SANE\_STATUS\_CANCELLED}:] The operation was cancelled through + a call to \code{sane\_cancel}. +\item[\code{SANE\_STATUS\_EOF}:] No more data is available for the + current frame. +\item[\code{SANE\_STATUS\_JAMMED}:] The document feeder is jammed. +\item[\code{SANE\_STATUS\_NO\_DOCS}:] The document feeder is out of + documents. +\item[\code{SANE\_STATUS\_COVER\_OPEN}:] The scanner cover is open. +\item[\code{SANE\_STATUS\_IO\_ERROR}:] An error occurred while communicating + with the device. +\item[\code{SANE\_STATUS\_NO\_MEM}:] An insufficent amount of memory + is available. +\item[\code{SANE\_STATUS\_ACCESS\_DENIED}:] Access to the device has + been denied due to insufficient or invalid authentication. +\end{description} +\end{quote} + + +\subsection{\code{sane\_cancel}} + +This function is used to immediately or as quickly as possible cancel +the currently pending operation of the device represented by handle +\code{h}. +\begin{quote}\index{sane\_cancel} +\begin{verbatim} +void sane_cancel (SANE_Handle h); +\end{verbatim} +\end{quote} +This function can be called at any time (as long as handle \code{h} is +a valid handle) but usually affects long-running operations only (such +as image is acquisition). It is safe to call this function +asynchronously (e.g., from within a signal handler). It is important +to note that completion of this operaton does {\em not\/} imply that +the currently pending operation has been cancelled. It only +guarantees that cancellation has been {\em initiated}. Cancellation +completes only when the cancelled call returns (typically with a +status value of \code{SANE\_STATUS\_CANCELLED}). Since the SANE API +does not require any other operations to be re-entrant, this implies +that a frontend must {\em not\/} call any other operation until the +cancelled operation has returned. + + +\subsection{\code{sane\_set\_io\_mode}} + +This function is used to set the I/O mode of handle \code{h}. The I/O +mode can be either blocking or non-blocking. If argument \code{m} is +\code{SANE\_TRUE}, the mode is set to non-blocking mode, otherwise +it's set to blocking mode. +\begin{quote}\index{sane\_set\_io\_mode} +\begin{verbatim} +SANE_Status sane_set_io_mode (SANE_Handle h, SANE_Bool m); +\end{verbatim} +\end{quote} +By default, newly opened handles operate in blocking mode. A backend +may elect not to support non-blocking I/O mode. In such a case the +status value \code{SANE\_STATUS\_UNSUPPORTED} is returned. Blocking +I/O must be supported by all backends, so calling this function with +argument \code{m} set to \code{SANE\_FALSE} is guaranteed to complete +successfully. + +This function may fail with one of the following status codes: +\begin{quote} +\begin{description} +\item[\code{SANE\_STATUS\_INVAL}:] No image acquisition is pending. +\item[\code{SANE\_STATUS\_UNSUPPORTED}:] The backend does not support + this operation. +\end{description} +\end{quote} + + +\subsection{\code{sane\_get\_select\_fd}} + +This function is used to obtain a (platform-specific) file-descriptor +for handle \code{h} that is readable if and only if image data is +available (i.e., when a call to \code{sane\_read()} will return at +least one byte of data). If the call completes successfully, the +select file-descriptor is returned in \code{*fd}. +\begin{quote}\index{sane\_get\_select\_fd} +\begin{verbatim} +SANE_Status sane_get_select_fd (SANE_Handle h, SANE_Int *fd); +\end{verbatim} +\end{quote} +This function can be called only after a call to \code{sane\_start()} +has been performed and the returned file-descriptor is guaranteed to +remain valid for the duration of the current image acquisition (i.e., +until \code{sane\_cancel()} or \code{sane\_start()} get called again +or until \code{sane\_read()} returns with status +\code{SANE\_STA\-TUS\_EOF}). Indeed, a backend must guarantee to +close the returned select file descriptor at the point when the next +\code{sane\_read()} call would return \code{SANE\_STA\-TUS\_EOF}. +This is necessary to ensure the application can detect when this +condition occurs without actually having to call \code{sane\_read()}. + +A backend may elect not to support this operation. In such a case, +the function returns with status code +\code{SANE\_STATUS\_UNSUPPORTED}. + +Note that the only operation supported by the returned file-descriptor +is a host operating-system dependent test whether the file-descriptor +is readable (e.g., this test can be implemented using \code{select()} +or \code{poll()} under UNIX). If any other operation is performed on +the file descriptor, the behavior of the backend becomes +unpredictable. Once the file-descriptor signals ``readable'' status, +it will remain in that state until a call to \code{sane\_read()} is +performed. Since many input devices are very slow, support for this +operation is strongly encouraged as it permits an application to do +other work while image acquisition is in progress. + +This function may fail with one of the following status codes: +\begin{quote} +\begin{description} +\item[\code{SANE\_STATUS\_INVAL}:] No image acquisition is pending. +\item[\code{SANE\_STATUS\_UNSUPPORTED}:] The backend does not support + this operation. +\end{description} +\end{quote} + + +\subsection{\code{sane\_strstatus}} + +This function can be used to translate a SANE status code into a +printable string. The returned string is a single line of text that +forms a complete sentence, but without the trailing period +(full-stop). The function is guaranteed to never return \code{NULL}. +The returned pointer is valid at least until the next call to this +function is performed. +\begin{quote}\index{sane\_strstatus} +\begin{verbatim} +const SANE_String_Const sane_strstatus (SANE_Status status); +\end{verbatim} +\end{quote} + +\section{Code Flow}\index{code flow} + +The code flow for the SANE API is illustrated in +Figure~\ref{fig:flow}. Functions \code{sane\_init()} and +\code{sane\_exit()} initialize and exit the backend, respectively. +All other calls must be performed after initialization and before +exiting the backend. + +\begin{figure}[htb] + \begin{center} + \leavevmode + \psfig{file=figs/flow.eps,height=0.5\textheight} + \caption{Code flow} + \label{fig:flow} + \end{center} +\end{figure} + +Function \code{sane\_get\_devices()} can be called any time after +\code{sane\_init()} has been called. It returns the list of the +devices that are known at the time of the call. This list may change +over time since some devices may be turned on or off or a remote host +may boot or shutdown between different calls. It should be noted that +this operation may be relatively slow since it requires contacting all +configured devices (some of which may be on remote hosts). A frontend +may therefore want to provide the ability for a user to directly +select a desired device without requiring a call to this function. + +Once a device has been chosen, it is opened using a call to +\code{sane\_open()}. Multiple devices can be open at any given time. +A SANE backend must not impose artificial constraints on how many +devices can be open at any given time. + +An opened device can be setup through the corresponding device handle +using functions \code{sane\_get\_opt\-ion\_desc\-riptor()} and +\code{sane\_control\_option()}. While setting up a device, obtaining +option descriptors and setting and reading of option values can be +mixed freely. It is typical for a frontend to read out all available +options at the beginning and then build a dialog (either graphical or +a command-line oriented option list) that allows to control the +available options. It should be noted that the number of options is +fixed for a given handle. However, as options are set, other options +may become active or inactive. Thus, after setting an option, it +maybe necessary to re-read some or all option descriptors. While +setting up the device, it is also admissible to call +\code{sane\_get\_parameters()} to get an estimate of what the image +parameters will look like once image acquisition begins. + +The device handle can be put in blocking or non-blocking mode by a +call to \code{sane\_set\_io\_mode()}. Devices are required to support +blocking mode (which is the default mode), but support for +non-blocking I/O is strongly encouraged for operating systems such as +UNIX. + +After the device is setup properly, image acquisition can be started +by a call to \code{sane\_start()}. The backend calculates the exact +image parameters at this point. So future calls to +\code{sane\_get\_parameters()} will return the exact values, rather +than estimates. Whether the physical image acquisition starts at this +point or during the first call to \code{sane\_read()} is unspecified +by the SANE API. If non-blocking I/O and/or a select-style interface +is desired, the frontend may attempt to call +\code{sane\_set\_io\_mode()} and/or \code{sane\_get\_select\_fd()} at +this point. Either of these functions may fail if the backend does +not support the requested operation. + +Image data is collected by repeatedly calling \code{sane\_read()}. +Eventually, this function will return an end-of-file status +(\code{SANE\_STATUS\_EOF}). This indicates the end of the current +frame. If the frontend expects additional frames (e.g., the +individual channels in of a red/green/blue image or multiple images), +it can call \code{sane\_start()} again. Once all desired frames have +been acquired, function \code{sane\_cancel()} must be called. This +operation can also be called at any other time to cancel a pending +operation. Note that \code{sane\_cancel()} must be called even if the +last read operation returned \code{SANE\_STATUS\_EOF}. + +When done using the device, the handle should be closed by a call to +\code{sane\_close()}. Finally, before exiting the application, +function \code{sane\_exit()} must be called. It is important not to +forget to call this function since otherwise some resources (e.g., +temporary files or locks) may remain unclaimed. + + +\section{Well-Known Options}\index{well-known options} + +While most backend options are completely self-describing, there are a +cases where a user interface might want to special-case the handling +of certain options. For example, the scan area is typically defined +by four options that specify the top-left and bottom-right corners of +the area. With a graphical user interface, it would be tedious to +force the user to type in these four numbers. Instead, most such +interfaces will want to present to the user a preview (low-resolution +scan) of the scanner surface and let the user pick the scan area by +dragging a rectangle into the desired position. For this reason, the +SANE API specifies a small number of option names that have +well-defined meanings. + +\subsection{Option Number Count}\index{option count} + +Option number 0 has an empty string as its name. The value of this +option is of type \code{SANE\_TYPE\_INT} and it specifies the total +number of options available for a given device (the count includes +option number 0). This means that there are two ways of counting the +number of options available: a frontend can either cycle through all +option numbers starting at one until +\code{sane\_get\_option\_descriptor()} returns \code{NULL}, or a +frontend can directly read out the value of option number 0. + +\subsection{Scan Resolution Option}\index{scan resolution}\index{resolution option} + +Option \code{resolution} is used to select the resolution at which an +image should be acquired. The type of this option is either +\code{SANE\_TYPE\_INT} or \code{SANE\_TYPE\_FIXED}. The unit is +\code{SANE\_UNIT\_DPI} (dots/inch). + +This option is not mandatory, but if a backend does support it, it +must implement it in a manner consistent with the above definition. + +\subsection{Preview Mode Option}\index{preview mode} + +The boolean option \code{preview} is used by a frontend to inform the +backend when image acquisition should be optimized for speed, rather +than quality (``preview mode''). When set to \code{SANE\_TRUE}, +preview mode is in effect, when set to \code{SANE\_FALSE} image +acquisition should proceed in normal quality mode. The setting of +this option \emph{must not\/} affect any other option. That is, as +far as the other options are concerned, the preview mode is completely +side effect free. A backend can assume that the frontend will take +care of appropriately setting the scan resolution for preview mode +(through option \code{resolution}). A backend is free to override the +\code{resolution} value with its own choice for preview mode, but it +is advised to leave this choice to the frontend wherever possible. + +This option is not mandatory, but if a backend does support it, it +must implement it in a manner consistent with the above definition. + +\subsection{Scan Area Options}\index{scan area options} + +The four most important well-known options are the ones that define +the scan area. The scan area is defined by two points (x/y coordinate +pairs) that specify the top-left and the bottom-right corners. This +is illustrated in Figure~\ref{fig:area}. Note that the origin of the +coordinate system is at the top-left corner of the scan surface as +seen by the sensor (which typically is a mirror image of the scan +surface seen by the user). For this reason, the top-left corner is +the corner for which the abscissa and ordinate values are +simultaneously the {\em smallest} and the bottom-right corner is the +corner for which the abscissa and ordinate values are simulatenously +the {\em largest}. If this coordinate system is not natural for a +given device, it is the job of the backend to perform the necessary +conversions. +\begin{figure}[tbp] + \begin{center} + \leavevmode + \psfig{file=figs/area.eps,height=0.3\textheight} + \caption{Scan area options} + \label{fig:area} + \end{center} +\end{figure} + +The names of the four options that define the scan area are given in +the table below: +\begin{center} +\begin{tabular}{ll} +{\bf Name} & {\bf Description} \\ +\code{\defn{tl-x}} & Top-left $x$ coordinate value \\ +\code{\defn{tl-y}} & Top-left $y$ coordinate value \\ +\code{\defn{br-x}} & Bottom-right $x$ coordinate value \\ +\code{\defn{br-y}} & Bottom-right $y$ coordinate value \\ +\end{tabular} +\end{center} +There are several rules that should be followed by front and backends +regarding these options: +\begin{itemize} + +\item Backends must attach a unit of either pixels + (\code{SANE\_UNIT\_PIXEL}) or millimeters (\code{SANE\_UNIT\_MM}) to + these options. The unit of all four options must be identical. + +\item Whenever meaningful, a backend should attach a range or a + word-list constraint to these options. + +\item A frontend can determine the size of the scan surface by first + checking that the options have range constraints associated. If a + range or word-list constraints exist, the frontend can take the + minimum and maximum values of one of the x and y option + range-constraints to determine the scan surface size. + +\item A frontend must work properly with any or all of these options + missing. + +\end{itemize} + +\input{net.tex} + +\chapter{Contact Information}\label{chap:contact} + +The SANE standard is discussed and evolved via a mailing list. +Anybody with email access to the Internet can automatically join and +leave the discussion group by sending mail to the following address. +\begin{quote}\index{mailing list} +\begin{verbatim} +majordomo@mostang.com +\end{verbatim} +\end{quote} +To subscribe, send a mail with the body ``\verb|subscribe sane-devel|'' to the +above address. + +A complete list of commands supported can be obtained by sending a +mail with a subject of ``\code{help}'' to the above address. The +mailing list is archived and available through the SANE home page at +URL: +\begin{quote} +\url{http://www.mostang.com/sane/} +\end{quote} + +\newpage +\input{sane.ind} + +\end{document} diff --git a/doc/xcam.man b/doc/xcam.man new file mode 100644 index 0000000..08cec81 --- /dev/null +++ b/doc/xcam.man @@ -0,0 +1,24 @@ +.TH xcam 1 "24 Jun 2000" +.IX xcam +.SH NAME +xcam - a graphical camera frontend for SANE +.SH SYNOPSIS +.B xcam + +.SH DESCRIPTION +Should be straightforward to use. Just be sure to use a very recent +version of GTK. + +.SH FILES +.TP +.I $HOME/.sane/xcam/devicename.rc +For each device, there is one rc-file that holds the saved settings +for that particular device. Normally, this file should not be +manipulated directly. Instead, the user should use the +.B xcam +interface to select appropriate values and then save the device +settings using the "Preferences->Save as default settings" menubar entry. +.SH "SEE ALSO" +xscanimage(1), scanimage(1), sane\-dll(5) and the backend manpages +.SH AUTHOR +David Mosberger-Tang diff --git a/doc/xscanimage.man b/doc/xscanimage.man new file mode 100644 index 0000000..a53ea6e --- /dev/null +++ b/doc/xscanimage.man @@ -0,0 +1,135 @@ +.TH xscanimage 1 "11 Aug 2000" +.IX xscanimage +.SH NAME +xscanimage - scan an image +.SH SYNOPSIS +.B xscanimage +.RB [ --display +.IR d ] +.RB [ --no-xshm ] +.RB [ --sync ] +.IR n ] +.RI [ devicename ] +.SH DESCRIPTION +.B xscanimage +provides a graphical user-interface to control an image +acquisition device such as a flatbed scanner or a camera. It allows +previewing and scanning invidual images and can be invoked either +directly from the command-line or through The GIMP image manipulation +program. In the former case, +.B xscanimage +acts as a stand-alone program that saves acquired images in a suitable +PNM format (PBM for black-and-white images, PGM for grayscale images, +and PPM for color images). In the latter case, the images are +directly passed to The GIMP for further processing. + +.B xscanimage +accesses image acquisition devices through the SANE (Scanner Access +Now Easy) interface. The list of available devices depends on +installed hardware and configuration. When invoked without an +explicit devicename argument, +.B xscanimage +presents a dialog listing all known and available devices. To access +an available device that is not known to the system, the devicename +must be specified explicitly. The format of devicename is +backendname:devicefile (eg umax:/dev/sga). +.SH RUNNING UNDER THE GIMP +To run +.B xscanimage +under the +.BR gimp (1), +simply copy it to one of the +.BR gimp (1) +plug-ins directories. If you want to conserve disk-space, you can +create a symlink instead. For example, for gimp-1.0.x the command +.PP +ln -s @BINDIR@/xscanimage ~/.gimp/plug-ins/ +.PP +and for gimp-1.1.x the command +.PP +ln -s @BINDIR@/xscanimage ~/.gimp-1.1/plug-ins/ +.PP +adds a symlink for the +.B xscanimage +binary to the user's plug-ins directory. After creating this symlink, +.B xscanimage +will be queried by +.BR gimp (1) +the next time it's invoked. From then on, +.B xscanimage +can be invoked through "Xtns->Acquire Image->Device dialog..." menu entry. + +You'll also find that the "Xtns->Acquire Image" menu contains short-cuts +to the SANE devices that were available at the time the +.B xscanimage +was queried. For example, the first PNM pseudo-device is typically +available as the short-cut "Xtns->Acquire Image->pnm:0". +Note that +.BR gimp (1) +caches these short-cuts in ~/.gimp/pluginrc. Thus, when the list of +available devices changes (e.g., a new scanner is installed), then it +is typically desirable to rebuild this cache. To do this, you can +either +.BR touch (1) +the +.B xscanimage +binary (e.g., "touch @BINDIR@/xscanimage") or delete the plug-ins cache +(e.g., "rm ~/.gimp/plug-ins"). Either way, invoking +.BR gimp (1) +afterwards will cause the pluginrc to be rebuilt. +.SH OPTIONS +.PP +The +.B --display +flag selects the X11 display used to present the graphical user-interface +(see +.BR X (1) +for details). +.PP +The +.B --no-xshm +flag requests not to use shared memory images. Shared memory images +usually enhance performance but cause problems with some buggy X11 +servers. Unless your X11 server dies when running this program, there +is no need or advantage to specify this flag. +.PP +The +.B --sync +flag requests a synchronous connection with the X11 server. This is for +debugging purposes only. +.SH FILES +.TP +.I $HOME/.sane/xscanimage/xscanimage.rc +This files holds the user preferences. Normally, this file should not +be manipulated directly. Instead, the user should customize the +program through the "Preferences" dialog. +.TP +.I $HOME/.sane/xscanimage/devicename.rc +For each device, there is one rc-file that holds the saved settings +for that particular device. Normally, this file should not be +manipulated directly. Instead, the user should use the +.B xscanimage +interface to select appropriate values and then save the device +settings using the "Preferences->Save Device Settings" menubar entry. +.TP +.I $HOME/.sane/preview-devicename.ppm +After acquiring a preview, +.B xscanimage +normally saves the preview image in this device-specific file. Thus, +next time the program is started up, the program can present the old +preview image. This feature can be turned off through the +"Preferences->Preview Options..." dialog. +.TP +.I @DATADIR@/sane-style.rc +This system-wide file controls the aspects of the user-interface such +as colors and fonts. It is a GTK style file and provides fine control +over the visual aspects of the user-interface. +.TP +.I $HOME/.sane/sane-style.rc +This file serves the same purpose as the system-wide style file. If +present, it takes precedence over the system wide style file. +.SH "SEE ALSO" +gimp(1), scanimage(1), sane-scsi(5), sane\-dll(5), sane\-net(5), +sane\-"backendname"(5) +.SH AUTHOR +Tristan Tarrant, Andreas Beck, and David Mosberger diff --git a/include/getopt.h b/include/getopt.h new file mode 100644 index 0000000..aa7877f --- /dev/null +++ b/include/getopt.h @@ -0,0 +1,129 @@ +/* Declarations for getopt. + Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc. + + 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/include/lalloca.h b/include/lalloca.h new file mode 100644 index 0000000..0fd4fc1 --- /dev/null +++ b/include/lalloca.h @@ -0,0 +1,47 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 The Free Software Foundation + This file is part of the SANE package. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a dynamic linking based SANE meta backend. It + allows managing an arbitrary number of SANE backends by using + dynamic linking to load backends on demand. */ + +#ifndef lalloca_h +#define lalloca_h + +/* AIX requires this to be the first thing in the file. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX +#pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +# if __STDC__ +void *alloca (); +# else +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +#endif /* lalloca_h */ diff --git a/include/sane/config.h.in b/include/sane/config.h.in new file mode 100644 index 0000000..28fffdc --- /dev/null +++ b/include/sane/config.h.in @@ -0,0 +1,342 @@ +#ifndef SANE_CONFIG_H +#define SANE_CONFIG_H + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +#undef _ALL_SOURCE +#endif + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +#undef CRAY_STACKSEG_END + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* Define if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define as __inline if that's what the C compiler calls it. */ +#undef inline + +/* Define if on MINIX. */ +#undef _MINIX + +/* Define to `long' if doesn't define. */ +#undef off_t + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +#undef _POSIX_1_SOURCE + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +/* Define to `unsigned char' if doesn't define. */ +#undef u_char + +/* Define to `unsigned int' if doesn't define. */ +#undef u_int + +/* Define to `unsigned long' if doesn't define. */ +#undef u_long + +/* Define to `long' if doesn't define. */ +#undef ssize_t + +/* Define to `int' if doesn't define. */ +#undef pid_t + +/* Define scsireq_t as `struct scsireq' if necessary. */ +#undef scsireq_t + +/* Define to the return type of signal handlers. */ +#undef RETSIGTYPE + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if NLS is requested. */ +#undef ENABLE_NLS + +/* Define as 1 if you have catgets and don't want to use GNU gettext. */ +#undef HAVE_CATGETS + +/* Define as 1 if you have gettext and don't want to use GNU gettext. */ +#undef HAVE_GETTEXT + +/* Define if your locale.h file contains LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES + +/* Define to 1 if you have the stpcpy function. */ +#undef HAVE_STPCPY + +/* Define to the name of the distribution. */ +#undef PACKAGE + +/* The concatenation of the strings PACKAGE, "-", and VERSION. */ +#undef PACKAGE_VERSION + +/* Define to the version of the distribution. */ +#undef VERSION + +/* Define if you have the __argz_count function. */ +#undef HAVE___ARGZ_COUNT + +/* Define if you have the __argz_next function. */ +#undef HAVE___ARGZ_NEXT + +/* Define if you have the __argz_stringify function. */ +#undef HAVE___ARGZ_STRINGIFY + +/* Define if you have the dcgettext function. */ +#undef HAVE_DCGETTEXT + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD + +/* Define if you have the getpagesize function. */ +#undef HAVE_GETPAGESIZE + +/* Define if you have the atexit function. */ +#undef HAVE_ATEXIT + +/* Define if you have the ioperm function. */ +#undef HAVE_IOPERM + +/* Define if you have the mkdir function. */ +#undef HAVE_MKDIR + +/* Define if you have the munmap function. */ +#undef HAVE_MUNMAP + +/* Define if you have the putenv function. */ +#undef HAVE_PUTENV + +/* Define if you have the scsireq_enter function. */ +#undef HAVE_SCSIREQ_ENTER + +/* Define if you have the sigprocmask function. */ +#undef HAVE_SIGPROCMASK + +/* Define if you have the setenv function. */ +#undef HAVE_SETENV + +/* Define if you have the setlocale function. */ +#undef HAVE_SETLOCALE + +/* Define if you have the stpcpy function. */ +#undef HAVE_STPCPY + +/* Define if you have the strcasecmp function. */ +#undef HAVE_STRCASECMP + +/* Define if you have the strchr function. */ +#undef HAVE_STRCHR + +/* Define if you have the strdup function. */ +#undef HAVE_STRDUP + +/* Define if you have the strncasecmp function. */ +#undef HAVE_STRNCASECMP + +/* Define if you have the strndup function. */ +#undef HAVE_STRNDUP + +/* Define if you have the strftime function. */ +#undef HAVE_STRFTIME + +/* Define if you have the strstr function. */ +#undef HAVE_STRSTR + +/* Define if you have the strsep function. */ +#undef HAVE_STRSEP + +/* Define if you have the strtod function. */ +#undef HAVE_STRTOD + +/* Define if you have the valloc function. */ +#undef HAVE_VALLOC + +/* Define if you have the snprintf function. */ +#undef HAVE_SNPRINTF + +/* Ignore HAVE_USLEEP under Apollo Domain because the usleep() + implementation in the Sys5.3 environment is broken. */ +#ifndef apollo + /* Define if you have the usleep function. */ +# undef HAVE_USLEEP +#endif + +/* Define if you have the header file. */ +#undef HAVE_ARGZ_H + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the header file. */ +#undef HAVE_LIBINTL_H + +/* Define if you have the header file. */ +#undef HAVE_LIBC_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define if you have the header file. */ +#undef HAVE_NL_TYPES_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_IO_H + +/* Define if you have the header file. */ +#undef HAVE_ASM_IO_H + +/* Define if you have the header file. */ +#undef HAVE_SCSI_H + +/* Define if you have the header file. */ +#undef HAVE_SCSI_SG_H + +/* Define if you have the "/usr/src/linux/include/scsi/sg.h" header file. */ +#undef HAVE__USR_SRC_LINUX_INCLUDE_SCSI_SG_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_DSREQ_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SCSI_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SCSI_TARGETS_SCGIO_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SCSI_SGDEFS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SCSICMD_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SCSIIO_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SCANIO_H + +/* Define if you have the header file. */ +#undef HAVE_APOLLO_SCSI_H + +/* Define if you have the header file. */ +#undef HAVE_BSD_DEV_SCSIREG_H + +/* Define if you have the header file. */ +#undef HAVE_IO_CAM_CAM_H + +/* Define if you have the header file. */ +#undef HAVE_CAMLIB_H + +/* Define if you have the header file. */ +#undef HAVE_GSCDDS_H + +/* Define if you have the header file. */ +#undef HAVE_OS2_H + +/* Define if you have EMX's sys/hw.h headers. */ +#undef HAVE_SYS_HW_H + +/* Define if you have sys/types.h. OS/2 wants them before select.h, etc. */ +#undef HAVE_SYS_TYPES_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the header file. */ +#undef HAVE_VALUES_H + +/* Define if you have the i library (-li). */ +#undef HAVE_LIBI + +/* Define if you have the intl library (-lintl). */ +#undef HAVE_LIBINTL + +/* Define if you have the m library (-lm). */ +#undef HAVE_LIBM + +/* Define if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define if you have the dlopen function. */ +#undef HAVE_DLOPEN + +/* Define if you have the header file. */ +#undef HAVE_DL_H + +/* Define if you have the shl_load function. */ +#undef HAVE_SHL_LOAD + +/* Define if you have the GIMP header files and library. */ +#undef HAVE_LIBGIMP_GIMP_H + +/* Define if you have the GIMPfeatures header file. */ +#undef HAVE_LIBGIMP_GIMPFEATURES_H + +/* Define if you have libjpeg. */ +#undef HAVE_LIBJPEG + +/* Define if you have libz. */ +#undef HAVE_LIBZ + +/* Define if you have libpng. */ +#undef HAVE_LIBPNG + +/* Define if you have libtiff. */ +#undef HAVE_LIBTIFF + +#ifndef HAVE_STRNCASECMP + /* OS/2 needs this */ +# define strncasecmp(a, b, c) strnicmp(a, b, c) +#endif + +#if defined (__sun) && defined (__GNUC__) +# define _POSIX_SOURCE +# define __EXTENSIONS__ +#endif + +#endif /* SANE_CONFIG_H */ diff --git a/include/sane/sanei.h b/include/sane/sanei.h new file mode 100644 index 0000000..93f75dd --- /dev/null +++ b/include/sane/sanei.h @@ -0,0 +1,42 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1996 David Mosberger-Tang and Andreas Beck + This file is part of the SANE package. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file declares SANE internal routines that are provided to + simplify backend implementation. */ + +#ifndef sanei_h +#define sanei_h + +#include + +/* A few convenience macros: */ + +#define STRINGIFY1(x) #x +#define STRINGIFY(x) STRINGIFY1(x) + +#define PASTE1(x,y) x##y +#define PASTE(x,y) PASTE1(x,y) + +#define NELEMS(a) ((int)(sizeof (a) / sizeof (a[0]))) + +extern SANE_Status sanei_constrain_value (const SANE_Option_Descriptor * opt, + void * value, SANE_Word * info); +extern int sanei_save_values (int fd, SANE_Handle device); +extern int sanei_load_values (int fd, SANE_Handle device); + +#endif /* sanei_h */ diff --git a/include/sane/sanei_backend.h b/include/sane/sanei_backend.h new file mode 100644 index 0000000..fe4a007 --- /dev/null +++ b/include/sane/sanei_backend.h @@ -0,0 +1,106 @@ +#include + +#ifdef HAVE_SYS_HW_H + /* OS/2 i/o-port access compatibility macros: */ +# define inb(p) _inp8 (p) +# define outb(v,p) _outp8 ((p),(v)) +# define ioperm(b,l,o) _portaccess ((b),(b)+(l)-1) +# define HAVE_IOPERM 1 +#endif + +#ifndef HAVE_OS2_H +#ifndef O_NONBLOCK +# ifdef O_NDELAY +# define O_NONBLOCK O_NDELAY +# else +# define O_NONBLOCK FNDELAY /* last resort */ +# endif +#endif +#endif /* HAVE_OS2_H */ + +#ifdef HAVE_SIGPROCMASK +# define SIGACTION sigaction +#else + +/* Just enough backwards compatibility that we get by in the backends + without making handstands. */ +# ifdef sigset_t +# undef sigset_t +# endif +# ifdef sigemptyset +# undef sigemptyset +# endif +# ifdef sigfillset +# undef sigfillset +# endif +# ifdef sigaddset +# undef sigaddset +# endif +# ifdef sigdelset +# undef sigdelset +# endif +# ifdef sigprocmask +# undef sigprocmask +# endif +# ifdef SIG_BLOCK +# undef SIG_BLOCK +# endif +# ifdef SIG_UNBLOCK +# undef SIG_UNBLOCK +# endif +# ifdef SIG_SETMASK +# undef SIG_SETMASK +# endif + +# define sigset_t int +# define sigemptyset(set) do { *(set) = 0; } while (0) +# define sigfillset(set) do { *(set) = ~0; } while (0) +# define sigaddset(set,signal) do { *(set) |= sigmask (signal); } while (0) +# define sigdelset(set,signal) do { *(set) &= ~sigmask (signal); } while (0) +# define sigaction(sig,new,old) sigvec (sig,new,old) + + /* Note: it's not safe to just declare our own "struct sigaction" since + some systems (e.g., some versions of OpenStep) declare that structure, + but do not implement sigprocmask(). Hard to believe, aint it? */ +# define SIGACTION sigvec +# define SIG_BLOCK 1 +# define SIG_UNBLOCK 2 +# define SIG_SETMASK 3 +#endif /* !HAVE_SIGPROCMASK */ + +/* Declare the entry points: */ + +extern SANE_Status ENTRY(init) (SANE_Int *, SANE_Auth_Callback); +extern SANE_Status ENTRY(get_devices) (const SANE_Device ***, SANE_Bool); +extern SANE_Status ENTRY(open) (SANE_String_Const, SANE_Handle *); +extern const SANE_Option_Descriptor * + ENTRY(get_option_descriptor) (SANE_Handle, SANE_Int); +extern SANE_Status ENTRY(control_option) (SANE_Handle, SANE_Int, SANE_Action, + void *, SANE_Word *); +extern SANE_Status ENTRY(get_parameters) (SANE_Handle, SANE_Parameters *); +extern SANE_Status ENTRY(start) (SANE_Handle); +extern SANE_Status ENTRY(read) (SANE_Handle, SANE_Byte *, SANE_Int, + SANE_Int *); +extern SANE_Status ENTRY(set_io_mode) (SANE_Handle, SANE_Bool); +extern SANE_Status ENTRY(get_select_fd) (SANE_Handle, SANE_Int *); +extern void ENTRY(cancel) (SANE_Handle); +extern void ENTRY(close) (SANE_Handle); +extern void ENTRY(exit) (void); + +#ifndef STUBS +/* Now redirect sane_* calls to backend's functions: */ + +#define sane_init(a,b) ENTRY(init) (a,b) +#define sane_get_devices(a,b) ENTRY(get_devices) (a,b) +#define sane_open(a,b) ENTRY(open) (a,b) +#define sane_get_option_descriptor(a,b) ENTRY(get_option_descriptor) (a,b) +#define sane_control_option(a,b,c,d,e) ENTRY(control_option) (a,b,c,d,e) +#define sane_get_parameters(a,b) ENTRY(get_parameters) (a,b) +#define sane_start(a) ENTRY(start) (a) +#define sane_read(a,b,c,d) ENTRY(read) (a,b,c,d) +#define sane_set_io_mode(a,b) ENTRY(set_io_mode) (a,b) +#define sane_get_select_fd(a,b) ENTRY(get_select_fd) (a,b) +#define sane_cancel(a) ENTRY(cancel) (a) +#define sane_close(a) ENTRY(close) (a) +#define sane_exit(a) ENTRY(exit) (a) +#endif /* STUBS */ diff --git a/include/sane/sanei_codec_ascii.h b/include/sane/sanei_codec_ascii.h new file mode 100644 index 0000000..1eb3a2a --- /dev/null +++ b/include/sane/sanei_codec_ascii.h @@ -0,0 +1,26 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1996 David Mosberger-Tang and Andreas Beck + This file is part of the SANE package. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file declares SANE application interface. See the SANE + standard for a detailed explanation of the interface. */ +#ifndef sanei_codec_ascii_h +#define sanei_codec_ascii_h + +extern void sanei_codec_ascii_init (Wire *w); + +#endif /* sanei_codec_ascii_h */ diff --git a/include/sane/sanei_codec_bin.h b/include/sane/sanei_codec_bin.h new file mode 100644 index 0000000..120a20f --- /dev/null +++ b/include/sane/sanei_codec_bin.h @@ -0,0 +1,26 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1996 David Mosberger-Tang and Andreas Beck + This file is part of the SANE package. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file declares SANE application interface. See the SANE + standard for a detailed explanation of the interface. */ +#ifndef sanei_codec_bin_h +#define sanei_codec_bin_h + +extern void sanei_codec_bin_init (Wire *w); + +#endif /* sanei_codec_bin_h */ diff --git a/include/sane/sanei_debug.h b/include/sane/sanei_debug.h new file mode 100644 index 0000000..7888a7c --- /dev/null +++ b/include/sane/sanei_debug.h @@ -0,0 +1,93 @@ +#ifndef _SANEI_DEBUG_H +#define _SANEI_DEBUG_H + +#include + +/* this header file defines: + * + * DBG_INIT() - should be called before any other debug function + * DBG(level, fmt, ...) - prints a message at debug level `level' or higher + * using a printf-like function + * IF_DBG(x) - expands to x if debug support is enabled at + * compile-time, if NDEBUG is defined at compile-time + * this macro expands to nothing + * + * ENTRY(name) - expands to sane_BACKEND_NAME_name + * + * before you include sanei_debug.h, you'll have to define + * + * BACKEND_NAME - the name of your backend without double-quotes + * STUBS - if this is defined, nothing will happen + * DEBUG_DECLARE_ONLY - generate prototypes instead of functions + * DEBUG_NOT_STATIC - doesn't generate static functions + * + */ + +#define ENTRY(name) PASTE(PASTE(PASTE(sane_,BACKEND_NAME),_),name) + +#ifdef NDEBUG + +extern void sanei_debug_ndebug (int level, const char *msg, ...); + +# define DBG_LEVEL (0) +# define DBG_INIT() +# define DBG sanei_debug_ndebug +# define IF_DBG(x) + +#else /* !NDEBUG */ + +# define DBG_LEVEL PASTE(sanei_debug_,BACKEND_NAME) + +# if defined(BACKEND_NAME) && !defined(STUBS) +# ifdef DEBUG_DECLARE_ONLY +extern int DBG_LEVEL; +# else /* !DEBUG_DECLARE_ONLY */ +int DBG_LEVEL = 0; +# endif /* DEBUG_DECLARE_ONLY */ +# endif /* BACKEND_NAME && !STUBS */ + +# define DBG_INIT() \ + sanei_init_debug (STRINGIFY(BACKEND_NAME), &DBG_LEVEL) + +# define DBG_LOCAL PASTE(DBG_LEVEL,_call) + + +# ifndef STUBS + +# ifdef DEBUG_DECLARE_ONLY + +extern void DBG_LOCAL (int level, const char *msg, ...); + +# else /* !DEBUG_DECLARE_ONLY */ + +# include + +extern void sanei_debug_msg + (int level, int max_level, const char *be, const char *fmt, va_list ap); + +# ifndef DEBUG_NOT_STATIC +static +# endif /* !DEBUG_NOT_STATIC */ +void +DBG_LOCAL (int level, const char *msg, ...) +{ + va_list ap; + + va_start (ap, msg); + sanei_debug_msg (level, DBG_LEVEL, STRINGIFY(BACKEND_NAME), msg, ap); + va_end (ap); +} + +# endif /* DEBUG_NOT_STATIC */ + +# endif /* !STUBS */ + +# define DBG DBG_LOCAL + +extern void sanei_init_debug (const char * backend, int * debug_level_var); + +# define IF_DBG(x) x + +#endif /* NDEBUG */ + +#endif /* _SANEI_DEBUG_H */ diff --git a/include/sane/sanei_pio.h b/include/sane/sanei_pio.h new file mode 100644 index 0000000..61ac414 --- /dev/null +++ b/include/sane/sanei_pio.h @@ -0,0 +1,55 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1998 Christian Bucher + Copyright (C) 1998 Kling & Hautzinger GmbH + This file is part of the SANE package. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +#ifndef sanei_pio_h +#define sanei_pio_h + +#include + +#include + +extern SANE_Status sanei_pio_open (const char * dev, int * fd); +extern void sanei_pio_close (int fd); +extern int sanei_pio_read (int fd, u_char * buf, int n); +extern int sanei_pio_write (int fd, const u_char * buf, int n); + +#endif /* sanei_pio_h */ + diff --git a/include/sane/sanei_signal.h b/include/sane/sanei_signal.h new file mode 100644 index 0000000..0033c1c --- /dev/null +++ b/include/sane/sanei_signal.h @@ -0,0 +1,50 @@ +#ifdef HAVE_SIGPROCMASK +# define SIGACTION sigaction +#else + +/* Just enough backwards compatibility that we get by in the backends + without making handstands. */ +# ifdef sigset_t +# undef sigset_t +# endif +# ifdef sigemptyset +# undef sigemptyset +# endif +# ifdef sigfillset +# undef sigfillset +# endif +# ifdef sigaddset +# undef sigaddset +# endif +# ifdef sigdelset +# undef sigdelset +# endif +# ifdef sigprocmask +# undef sigprocmask +# endif +# ifdef SIG_BLOCK +# undef SIG_BLOCK +# endif +# ifdef SIG_UNBLOCK +# undef SIG_UNBLOCK +# endif +# ifdef SIG_SETMASK +# undef SIG_SETMASK +# endif + +# define sigset_t int +# define sigemptyset(set) do { *(set) = 0; } while (0) +# define sigfillset(set) do { *(set) = ~0; } while (0) +# define sigaddset(set,signal) do { *(set) |= sigmask (signal); } while (0) +# define sigdelset(set,signal) do { *(set) &= ~sigmask (signal); } while (0) +# define sigaction(sig,new,old) sigvec (sig,new,old) + + /* Note: it's not safe to just declare our own "struct sigaction" since + some systems (e.g., some versions of OpenStep) declare that structure, + but do not implement sigprocmask(). Hard to believe, aint it? */ +# define SIGACTION sigvec +# define SIG_BLOCK 1 +# define SIG_UNBLOCK 2 +# define SIG_SETMASK 3 +#endif /* !HAVE_SIGPROCMASK */ + diff --git a/include/sane/sanei_thread.h b/include/sane/sanei_thread.h new file mode 100644 index 0000000..977b84d --- /dev/null +++ b/include/sane/sanei_thread.h @@ -0,0 +1,33 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 2000 Yuri Dario + This file is part of the SANE package. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file declares a _proposed_ internal SANE interface. It was + proposed 2000-02-19 by Yuri Dario to wrap UNIX functions fork(), + kill(), waitpid() and wait(), which are missing on OS/2. +*/ + +#ifndef sanei_thread_h +#define sanei_thread_h + +extern int sanei_thread_begin( void (*start)(void *arg), + void *arg_list); +extern int sanei_thread_kill( int pid, int sig); +extern int sanei_thread_waitpid( int pid, int *stat_loc, int options); +extern int sanei_thread_wait( int *stat_loc); + +#endif /* sanei_thread_h */ diff --git a/include/sane/sanei_wire.h b/include/sane/sanei_wire.h new file mode 100644 index 0000000..3c380a0 --- /dev/null +++ b/include/sane/sanei_wire.h @@ -0,0 +1,104 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Support routines to translate internal datatypes into a wire-format + (used for RPCs and to save/restore options). */ + +#ifndef sanei_wire_h +#define sanei_wire_h + +#include + +typedef enum + { + WIRE_ENCODE = 0, + WIRE_DECODE, + WIRE_FREE + } +WireDirection; + +struct Wire; + +typedef void (*WireCodecFunc) (struct Wire *w, void *val_ptr); +typedef ssize_t (*WireReadFunc) (int fd, void * buf, size_t len); +typedef ssize_t (*WireWriteFunc) (int fd, const void * buf, size_t len); + +typedef struct Wire + { + int version; /* protocol version in use */ + WireDirection direction; + int status; + struct + { + WireCodecFunc w_byte; + WireCodecFunc w_char; + WireCodecFunc w_word; + WireCodecFunc w_string; + } + codec; + struct + { + size_t size; + char *curr; + char *start; + char *end; + } + buffer; + struct + { + int fd; + WireReadFunc read; + WireWriteFunc write; + } + io; + } +Wire; + +extern void sanei_w_init (Wire *w, void (*codec_init)(Wire *)); +extern void sanei_w_space (Wire *w, size_t howmuch); +extern void sanei_w_void (Wire *w); +extern void sanei_w_byte (Wire *w, SANE_Byte *v); +extern void sanei_w_char (Wire *w, SANE_Char *v); +extern void sanei_w_word (Wire *w, SANE_Word *v); +extern void sanei_w_string (Wire *w, SANE_String *v); +extern void sanei_w_status (Wire *w, SANE_Status *v); +extern void sanei_w_constraint_type (Wire *w, SANE_Constraint_Type *v); +extern void sanei_w_value_type (Wire *w, SANE_Value_Type *v); +extern void sanei_w_unit (Wire *w, SANE_Unit *v); +extern void sanei_w_action (Wire *w, SANE_Action *v); +extern void sanei_w_frame (Wire *w, SANE_Frame *v); +extern void sanei_w_range (Wire *w, SANE_Range *v); +extern void sanei_w_range_ptr (Wire *w, SANE_Range **v); +extern void sanei_w_device (Wire *w, SANE_Device *v); +extern void sanei_w_device_ptr (Wire *w, SANE_Device **v); +extern void sanei_w_option_descriptor (Wire *w, SANE_Option_Descriptor *v); +extern void sanei_w_option_descriptor_ptr (Wire *w, + SANE_Option_Descriptor **v); +extern void sanei_w_parameters (Wire *w, SANE_Parameters *v); + +extern void sanei_w_array (Wire *w, SANE_Word *len, void **v, + WireCodecFunc w_element, size_t element_size); + +extern void sanei_w_set_dir (Wire *w, WireDirection dir); +extern void sanei_w_call (Wire *w, SANE_Word proc_num, + WireCodecFunc w_arg, void *arg, + WireCodecFunc w_reply, void *reply); +extern void sanei_w_reply (Wire *w, WireCodecFunc w_reply, void *reply); +extern void sanei_w_free (Wire *w, WireCodecFunc w_reply, void *reply); + +#endif /* sanei_wire_h */ diff --git a/include/sane/stamp-h b/include/sane/stamp-h new file mode 100644 index 0000000..9788f70 --- /dev/null +++ b/include/sane/stamp-h @@ -0,0 +1 @@ +timestamp diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..178cdac --- /dev/null +++ b/install-sh @@ -0,0 +1,250 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 0000000..a56358b --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,77 @@ +SHELL = /bin/sh + +VPATH = @srcdir@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = .. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +configdir = ${sysconfdir}/sane.d +sanedatadir = ${datadir}/sane + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +INCLUDES = -I. -I$(srcdir) \ + -I$(top_builddir)/include/sane -I$(top_srcdir)/include +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +DEFS = @DEFS@ + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) + +@SET_MAKE@ + +LIBLIB_OBJS = alloca.o getopt.o getopt1.o strndup.o \ + strdup.o strsep.o snprintf.o usleep.o +LIBLIB_LTOBJS = alloca.lo getopt.lo getopt1.lo strndup.lo \ + strdup.lo strsep.lo snprintf.lo usleep.lo + +TARGETS = $(LIBLIB_OBJS) +TARGETS = liblib.a + +.SUFFIXES: +.SUFFIXES: .c .o +.c.o: + $(COMPILE) $< + @test -f $@ || $(COMPILE) $< + +all: $(TARGETS) + +liblib.a: $(LIBLIB_OBJS) + ar r $@ $(LIBLIB_OBJS) + +install: all + +uninstall: + +check: + +depend: + makedepend -I. -I../include *.c + +clean: + rm -f *.out *.o *.lo *~ *.a *.bak $(TESTPROGRAMS) + rm -rf .libs + +distclean: clean + rm -f Makefile + +.PHONY: all install check depend clean distclean diff --git a/lib/alloca.c b/lib/alloca.c new file mode 100644 index 0000000..16f7e86 --- /dev/null +++ b/lib/alloca.c @@ -0,0 +1,493 @@ +/* alloca.c -- allocate automatically reclaimed memory + (Mostly) portable public-domain implementation -- D A Gwyn + + This implementation of the PWB library alloca function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + J.Otto Tennant contributed the Cray support. + + There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef HAVE_ALLOCA + +#ifdef emacs +#include "blockinput.h" +#endif + +/* If compiling with GCC 2, this file's not needed. */ +#if !defined (__GNUC__) || __GNUC__ < 2 + +/* If someone has defined alloca as a macro, + there must be some other way alloca is supposed to work. */ +#ifndef alloca + +#ifdef emacs +#ifdef static +/* actually, only want this if static is defined as "" + -- this is for usg, in which emacs must undefine static + in order to make unexec workable + */ +#ifndef STACK_DIRECTION +you +lose +-- must know STACK_DIRECTION at compile-time +#endif /* STACK_DIRECTION undefined */ +#endif /* static */ +#endif /* emacs */ + +/* If your stack is a linked list of frames, you have to + provide an "address metric" ADDRESS_FUNCTION macro. */ + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) +long i00afunc (); +#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg)) +#else +#define ADDRESS_FUNCTION(arg) &(arg) +#endif + +#if __STDC__ +typedef void *pointer; +#else +typedef char *pointer; +#endif + +#define NULL 0 + +/* Different portions of Emacs need to call different versions of + malloc. The Emacs executable needs alloca to call xmalloc, because + ordinary malloc isn't protected from input signals. On the other + hand, the utilities in lib-src need alloca to call malloc; some of + them are very simple, and don't have an xmalloc routine. + + Non-Emacs programs expect this to call xmalloc. + + Callers below should use malloc. */ + +extern pointer malloc (); + +/* Define STACK_DIRECTION if you know the direction of stack + growth for your system; otherwise it will be automatically + deduced at run-time. + + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ + +#ifndef STACK_DIRECTION +#define STACK_DIRECTION 0 /* Direction unknown. */ +#endif + +#if STACK_DIRECTION != 0 + +#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */ + +#else /* STACK_DIRECTION == 0; need run-time code. */ + +static int stack_dir; /* 1 or -1 once known. */ +#define STACK_DIR stack_dir + +static void +find_stack_direction () +{ + static char *addr = NULL; /* Address of first `dummy', once known. */ + auto char dummy; /* To get stack address. */ + + if (addr == NULL) + { /* Initial entry. */ + addr = ADDRESS_FUNCTION (dummy); + + find_stack_direction (); /* Recurse once. */ + } + else + { + /* Second entry. */ + if (ADDRESS_FUNCTION (dummy) > addr) + stack_dir = 1; /* Stack grew upward. */ + else + stack_dir = -1; /* Stack grew downward. */ + } +} + +#endif /* STACK_DIRECTION == 0 */ + +/* An "alloca header" is used to: + (a) chain together all alloca'ed blocks; + (b) keep track of stack depth. + + It is very important that sizeof(header) agree with malloc + alignment chunk size. The following default should work okay. */ + +#ifndef ALIGN_SIZE +#define ALIGN_SIZE sizeof(double) +#endif + +typedef union hdr +{ + char align[ALIGN_SIZE]; /* To force sizeof(header). */ + struct + { + union hdr *next; /* For chaining headers. */ + char *deep; /* For stack depth measure. */ + } h; +} header; + +static header *last_alloca_header = NULL; /* -> last alloca header. */ + +/* Return a pointer to at least SIZE bytes of storage, + which will be automatically reclaimed upon exit from + the procedure that called alloca. Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. */ + +pointer +alloca (size) + unsigned size; +{ + auto char probe; /* Probes stack depth: */ + register char *depth = ADDRESS_FUNCTION (probe); + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* Unknown growth direction. */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca'd storage that + was allocated from deeper in the stack than currently. */ + + { + register header *hp; /* Traverses linked list. */ + +#ifdef emacs + BLOCK_INPUT; +#endif + + for (hp = last_alloca_header; hp != NULL;) + if ((STACK_DIR > 0 && hp->h.deep > depth) + || (STACK_DIR < 0 && hp->h.deep < depth)) + { + register header *np = hp->h.next; + + free ((pointer) hp); /* Collect garbage. */ + + hp = np; /* -> next header. */ + } + else + break; /* Rest are not deeper. */ + + last_alloca_header = hp; /* -> last valid storage. */ + +#ifdef emacs + UNBLOCK_INPUT; +#endif + } + + if (size == 0) + return NULL; /* No allocation required. */ + + /* Allocate combined header + user data storage. */ + + { + register pointer new = malloc (sizeof (header) + size); + /* Address of header. */ + + ((header *) new)->h.next = last_alloca_header; + ((header *) new)->h.deep = depth; + + last_alloca_header = (header *) new; + + /* User storage begins just after header. */ + + return (pointer) ((char *) new + sizeof (header)); + } +} + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) + +#ifdef DEBUG_I00AFUNC +#include +#endif + +#ifndef CRAY_STACK +#define CRAY_STACK +#ifndef CRAY2 +/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */ +struct stack_control_header + { + long shgrow:32; /* Number of times stack has grown. */ + long shaseg:32; /* Size of increments to stack. */ + long shhwm:32; /* High water mark of stack. */ + long shsize:32; /* Current size of stack (all segments). */ + }; + +/* The stack segment linkage control information occurs at + the high-address end of a stack segment. (The stack + grows from low addresses to high addresses.) The initial + part of the stack segment linkage control information is + 0200 (octal) words. This provides for register storage + for the routine which overflows the stack. */ + +struct stack_segment_linkage + { + long ss[0200]; /* 0200 overflow words. */ + long sssize:32; /* Number of words in this segment. */ + long ssbase:32; /* Offset to stack base. */ + long:32; + long sspseg:32; /* Offset to linkage control of previous + segment of stack. */ + long:32; + long sstcpt:32; /* Pointer to task common address block. */ + long sscsnm; /* Private control structure number for + microtasking. */ + long ssusr1; /* Reserved for user. */ + long ssusr2; /* Reserved for user. */ + long sstpid; /* Process ID for pid based multi-tasking. */ + long ssgvup; /* Pointer to multitasking thread giveup. */ + long sscray[7]; /* Reserved for Cray Research. */ + long ssa0; + long ssa1; + long ssa2; + long ssa3; + long ssa4; + long ssa5; + long ssa6; + long ssa7; + long sss0; + long sss1; + long sss2; + long sss3; + long sss4; + long sss5; + long sss6; + long sss7; + }; + +#else /* CRAY2 */ +/* The following structure defines the vector of words + returned by the STKSTAT library routine. */ +struct stk_stat + { + long now; /* Current total stack size. */ + long maxc; /* Amount of contiguous space which would + be required to satisfy the maximum + stack demand to date. */ + long high_water; /* Stack high-water mark. */ + long overflows; /* Number of stack overflow ($STKOFEN) calls. */ + long hits; /* Number of internal buffer hits. */ + long extends; /* Number of block extensions. */ + long stko_mallocs; /* Block allocations by $STKOFEN. */ + long underflows; /* Number of stack underflow calls ($STKRETN). */ + long stko_free; /* Number of deallocations by $STKRETN. */ + long stkm_free; /* Number of deallocations by $STKMRET. */ + long segments; /* Current number of stack segments. */ + long maxs; /* Maximum number of stack segments so far. */ + long pad_size; /* Stack pad size. */ + long current_address; /* Current stack segment address. */ + long current_size; /* Current stack segment size. This + number is actually corrupted by STKSTAT to + include the fifteen word trailer area. */ + long initial_address; /* Address of initial segment. */ + long initial_size; /* Size of initial segment. */ + }; + +/* The following structure describes the data structure which trails + any stack segment. I think that the description in 'asdef' is + out of date. I only describe the parts that I am sure about. */ + +struct stk_trailer + { + long this_address; /* Address of this block. */ + long this_size; /* Size of this block (does not include + this trailer). */ + long unknown2; + long unknown3; + long link; /* Address of trailer block of previous + segment. */ + long unknown5; + long unknown6; + long unknown7; + long unknown8; + long unknown9; + long unknown10; + long unknown11; + long unknown12; + long unknown13; + long unknown14; + }; + +#endif /* CRAY2 */ +#endif /* not CRAY_STACK */ + +#ifdef CRAY2 +/* Determine a "stack measure" for an arbitrary ADDRESS. + I doubt that "lint" will like this much. */ + +static long +i00afunc (long *address) +{ + struct stk_stat status; + struct stk_trailer *trailer; + long *block, size; + long result = 0; + + /* We want to iterate through all of the segments. The first + step is to get the stack status structure. We could do this + more quickly and more directly, perhaps, by referencing the + $LM00 common block, but I know that this works. */ + + STKSTAT (&status); + + /* Set up the iteration. */ + + trailer = (struct stk_trailer *) (status.current_address + + status.current_size + - 15); + + /* There must be at least one stack segment. Therefore it is + a fatal error if "trailer" is null. */ + + if (trailer == 0) + abort (); + + /* Discard segments that do not contain our argument address. */ + + while (trailer != 0) + { + block = (long *) trailer->this_address; + size = trailer->this_size; + if (block == 0 || size == 0) + abort (); + trailer = (struct stk_trailer *) trailer->link; + if ((block <= address) && (address < (block + size))) + break; + } + + /* Set the result to the offset in this segment and add the sizes + of all predecessor segments. */ + + result = address - block; + + if (trailer == 0) + { + return result; + } + + do + { + if (trailer->this_size <= 0) + abort (); + result += trailer->this_size; + trailer = (struct stk_trailer *) trailer->link; + } + while (trailer != 0); + + /* We are done. Note that if you present a bogus address (one + not in any segment), you will get a different number back, formed + from subtracting the address of the first block. This is probably + not what you want. */ + + return (result); +} + +#else /* not CRAY2 */ +/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP. + Determine the number of the cell within the stack, + given the address of the cell. The purpose of this + routine is to linearize, in some sense, stack addresses + for alloca. */ + +static long +i00afunc (long address) +{ + long stkl = 0; + + long size, pseg, this_segment, stack; + long result = 0; + + struct stack_segment_linkage *ssptr; + + /* Register B67 contains the address of the end of the + current stack segment. If you (as a subprogram) store + your registers on the stack and find that you are past + the contents of B67, you have overflowed the segment. + + B67 also points to the stack segment linkage control + area, which is what we are really interested in. */ + + stkl = CRAY_STACKSEG_END (); + ssptr = (struct stack_segment_linkage *) stkl; + + /* If one subtracts 'size' from the end of the segment, + one has the address of the first word of the segment. + + If this is not the first segment, 'pseg' will be + nonzero. */ + + pseg = ssptr->sspseg; + size = ssptr->sssize; + + this_segment = stkl - size; + + /* It is possible that calling this routine itself caused + a stack overflow. Discard stack segments which do not + contain the target address. */ + + while (!(this_segment <= address && address <= stkl)) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl); +#endif + if (pseg == 0) + break; + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + this_segment = stkl - size; + } + + result = address - this_segment; + + /* If you subtract pseg from the current end of the stack, + you get the address of the previous stack segment's end. + This seems a little convoluted to me, but I'll bet you save + a cycle somewhere. */ + + while (pseg != 0) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o\n", pseg, size); +#endif + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + result += size; + } + return (result); +} + +#endif /* not CRAY2 */ +#endif /* CRAY */ + +#endif /* no alloca */ +#endif /* not GCC version 2 */ + +#endif /* !HAVE_ALLOCA */ diff --git a/lib/getopt.c b/lib/getopt.c new file mode 100644 index 0000000..91f00b5 --- /dev/null +++ b/lib/getopt.c @@ -0,0 +1,831 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 1996 + Free Software Foundation, Inc. + + 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, 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#if defined (_LIBC) || defined (HAVE_UNISTD_H) +#include +#endif +#endif /* GNU C library. */ + +#ifdef VMS +#include +#if HAVE_STRING_H - 0 +#include +#endif +#endif + +#ifdef WIN32 +/* It's not Unix, really. See? Capital letters. */ +#include +#define getpid() GetCurrentProcessId() +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +#ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +#else +# define _(msgid) (msgid) +#endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#if !defined (__STDC__) || !__STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +static const char *nonoption_flags; +static int nonoption_flags_len; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined (__STDC__) && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined (__STDC__) && __STDC__ +static const char *_getopt_initialize (const char *); +#endif +static const char * +_getopt_initialize (optstring) + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + + if (posixly_correct == NULL) + { + /* Bash 2.0 puts a special variable in the environment for each + command it runs, specifying which ARGV elements are the results of + file name wildcard expansion and therefore should not be + considered as options. */ + char var[100]; + sprintf (var, "_%d_GNU_nonoption_argv_flags_", getpid ()); + nonoption_flags = getenv (var); + if (nonoption_flags == NULL) + nonoption_flags_len = 0; + else + nonoption_flags_len = strlen (nonoption_flags); + } + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0) + { + optstring = _getopt_initialize (optstring); + optind = 1; /* Don't scan ARGV[0], the program name. */ + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. */ +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && nonoption_flags[optind] == '1')) + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + +#ifdef lint /* Suppress `used before initialized' warning. */ + indfound = 0; +#endif + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if (nameend - nextchar == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/lib/getopt1.c b/lib/getopt1.c new file mode 100644 index 0000000..7cf0bfb --- /dev/null +++ b/lib/getopt1.c @@ -0,0 +1,180 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994 + Free Software Foundation, Inc. + + 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, 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#else +char *getenv (); +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == EOF) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/lib/snprintf.c b/lib/snprintf.c new file mode 100644 index 0000000..059d48c --- /dev/null +++ b/lib/snprintf.c @@ -0,0 +1,532 @@ +#include + +#ifndef HAVE_SNPRINTF + +/*************************************************************************** + * LPRng - An Extended Print Spooler System + * + * Copyright 1988-1997, Patrick Powell, San Diego, CA + * papowell@sdsu.edu + * See below for conditions of use. + * + *************************************************************************** + * MODULE: snprintf.c + * PURPOSE: LPRng version of printf - absolutely bombproof (hopefully!) + **************************************************************************/ +#if 0 + + The "Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you are thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site such as uunet.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this +Package. You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you do not advertise this Package as a +product of your own. + +6. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +7. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End +#include "lp.h" +#endif + +#include +#include +#include +#define HAVE_STDARGS /* let's hope that works everywhere (mj) */ +#define VA_LOCAL_DECL va_list ap; +#define VA_START(f) va_start(ap, f) +#define VA_SHIFT(v,t) ; /* no-op for ANSI */ +#define VA_END va_end(ap) + +/**** ENDINCLUDE ****/ + +static char *const _id = "$Id$"; + +/* + * dopr(): poor man's version of doprintf + */ + +static char * plp_Errormsg ( int err ); +static void dopr( char *buffer, const char *format, va_list args ); +static void fmtstr( char *value, int ljust, int len, int zpad, int precision ); +static void fmtnum( long value, int base, int dosign, + int ljust, int len, int zpad, int precision ); +static void fmtdouble( int fmt, double value, + int ljust, int len, int zpad, int precision ); +static void dostr( char * ); +static char *output; +static void dopr_outch( int c ); +static char *end; +int visible_control = 1; + +/************************************************************** + * Original: + * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 + * A bombproof version of doprnt (dopr) included. + * Sigh. This sort of thing is always nasty do deal with. Note that + * the version here does not include floating point... + * + * plp_snprintf() is used instead of sprintf() as it does limit checks + * for string length. This covers a nasty loophole. + * + * The other functions are there to prevent NULL pointers from + * causing nast effects. + **************************************************************/ + +int vsnprintf(char *str, size_t count, const char *fmt, va_list args) +{ + str[0] = 0; + end = str+count-1; + dopr( str, fmt, args ); + if( count>0 ){ + end[0] = 0; + } + return(strlen(str)); +} + +/* VARARGS3 */ +#ifdef HAVE_STDARGS +int snprintf (char *str,size_t count,const char *fmt,...) +#else +int snprintf (va_alist) va_dcl +#endif +{ +#ifndef HAVE_STDARGS + char *str; + size_t count; + char *fmt; +#endif + VA_LOCAL_DECL + + VA_START (fmt); + VA_SHIFT (str, char *); + VA_SHIFT (count, size_t ); + VA_SHIFT (fmt, char *); + (void) vsnprintf ( str, count, fmt, ap); + VA_END; + return( strlen( str ) ); +} + +static void dopr( char *buffer, const char *format, va_list args ) +{ + int ch; + long value; + int longflag = 0; + char *strvalue; + int ljust; + int len; + int zpad; + int precision; + int set_precision; + double dval; + int err = errno; + + output = buffer; + while( (ch = *format++) ){ + switch( ch ){ + case '%': + ljust = len = zpad = 0; + precision = -1; set_precision = 0; + nextch: + ch = *format++; + switch( ch ){ + case 0: + dostr( "**end of format**" ); + return; + case '-': ljust = 1; goto nextch; + case '.': set_precision = 1; precision = 0; goto nextch; + case '*': len = va_arg( args, int ); goto nextch; + case '0': /* set zero padding if len not set */ + if(len==0 && set_precision == 0 ) zpad = '0'; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + if( set_precision ){ + precision = precision*10 + ch - '0'; + } else { + len = len*10 + ch - '0'; + } + goto nextch; + case 'l': longflag = 1; goto nextch; + case 'u': case 'U': + /*fmtnum(value,base,dosign,ljust,len, zpad, precision) */ + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 10,0, ljust, len, zpad, precision ); break; + case 'o': case 'O': + /*fmtnum(value,base,dosign,ljust,len, zpad, precision) */ + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 8,0, ljust, len, zpad, precision ); break; + case 'd': case 'D': + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 10,1, ljust, len, zpad, precision ); break; + case 'x': + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value, 16,0, ljust, len, zpad, precision ); break; + case 'X': + if( longflag ){ + value = va_arg( args, long ); + } else { + value = va_arg( args, int ); + } + fmtnum( value,-16,0, ljust, len, zpad, precision ); break; + case 's': + strvalue = va_arg( args, char *); + fmtstr( strvalue,ljust,len, zpad, precision ); + break; + case 'c': + ch = va_arg( args, int ); + { char b[2]; + int vsb = visible_control; + b[0] = ch; + b[1] = 0; + visible_control = 0; + fmtstr( b,ljust,len, zpad, precision ); + visible_control = vsb; + } + break; + case 'f': case 'g': + dval = va_arg( args, double ); + fmtdouble( ch, dval,ljust,len, zpad, precision ); break; + case 'm': + fmtstr( plp_Errormsg(err),ljust,len, zpad, precision ); break; + case '%': dopr_outch( ch ); continue; + default: + dostr( "???????" ); + } + longflag = 0; + break; + default: + dopr_outch( ch ); + break; + } + } + *output = 0; +} + +/* + * Format '%[-]len[.precision]s' + * - = left justify (ljust) + * len = minimum length + * precision = numbers of chars in string to use + */ +static void +fmtstr( char *value, int ljust, int len, int zpad, int precision ) +{ + int padlen, strlen, i, c; /* amount to pad */ + + if( value == 0 ){ + value = ""; + } + if( precision > 0 ){ + strlen = precision; + } else { + /* cheap strlen so you do not have library call */ + for( strlen = 0; (c=value[strlen]); ++ strlen ){ + if( visible_control && iscntrl( c ) && !isspace( c ) ){ + ++strlen; + } + } + } + padlen = len - strlen; + if( padlen < 0 ) padlen = 0; + if( ljust ) padlen = -padlen; + while( padlen > 0 ) { + dopr_outch( ' ' ); + --padlen; + } + /* output characters */ + for( i = 0; (c = value[i]); ++i ){ + if( visible_control && iscntrl( c ) && !isspace( c ) ){ + dopr_outch('^'); + c = ('@' | (c & 0x1F)); + } + dopr_outch(c); + } + while( padlen < 0 ) { + dopr_outch( ' ' ); + ++padlen; + } +} + +static void +fmtnum( long value, int base, int dosign, int ljust, + int len, int zpad, int precision ) +{ + int signvalue = 0; + unsigned long uvalue; + char convert[20]; + int place = 0; + int padlen = 0; /* amount to pad */ + int caps = 0; + + /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n", + value, base, dosign, ljust, len, zpad )); */ + uvalue = value; + if( dosign ){ + if( value < 0 ) { + signvalue = '-'; + uvalue = -value; + } + } + if( base < 0 ){ + caps = 1; + base = -base; + } + do{ + convert[place++] = + (caps? "0123456789ABCDEF":"0123456789abcdef") + [uvalue % (unsigned)base ]; + uvalue = (uvalue / (unsigned)base ); + }while(uvalue); + convert[place] = 0; + padlen = len - place; + if( padlen < 0 ) padlen = 0; + if( ljust ) padlen = -padlen; + /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n", + convert,place,signvalue,padlen)); */ + if( zpad && padlen > 0 ){ + if( signvalue ){ + dopr_outch( signvalue ); + --padlen; + signvalue = 0; + } + while( padlen > 0 ){ + dopr_outch( zpad ); + --padlen; + } + } + while( padlen > 0 ) { + dopr_outch( ' ' ); + --padlen; + } + if( signvalue ) dopr_outch( signvalue ); + while( place > 0 ) dopr_outch( convert[--place] ); + while( padlen < 0 ){ + dopr_outch( ' ' ); + ++padlen; + } +} + +static void +fmtdouble( int fmt, double value, int ljust, int len, int zpad, int precision ) +{ + char convert[128]; + char fmtstr[128]; + int l; + + if( len == 0 ) len = 10; + if( len > sizeof(convert) - 10 ){ + len = sizeof(convert) - 10; + } + if( precision > sizeof(convert) - 10 ){ + precision = sizeof(convert) - 10; + } + if( precision > len ) precision = len; + strcpy( fmtstr, "%" ); + if( ljust ) strcat(fmtstr, "-" ); + if( len ){ + sprintf( fmtstr+strlen(fmtstr), "%d", len ); + } + if( precision > 0 ){ + sprintf( fmtstr+strlen(fmtstr), ".%d", precision ); + } + l = strlen( fmtstr ); + fmtstr[l] = fmt; + fmtstr[l+1] = 0; + sprintf( convert, fmtstr, value ); + dostr( convert ); +} + +static void dostr( char *str ) +{ + while(*str) dopr_outch(*str++); +} + +static void dopr_outch( int c ) +{ + if( end == 0 || output < end ){ + *output++ = c; + } +} + + +/**************************************************************************** + * static char *plp_errormsg( int err ) + * returns a printable form of the + * errormessage corresponding to the valie of err. + * This is the poor man's version of sperror(), not available on all systems + * Patrick Powell Tue Apr 11 08:05:05 PDT 1995 + ****************************************************************************/ +/****************************************************************************/ +#if !defined(HAVE_STRERROR) + +# if defined(HAVE_SYS_NERR) +# if !defined(HAVE_SYS_NERR_DEF) + extern int sys_nerr; +# endif +# define num_errors (sys_nerr) +# else +# define num_errors (-1) /* always use "errno=%d" */ +# endif + +# if defined(HAVE_SYS_ERRLIST) +# if !defined(HAVE_SYS_ERRLIST_DEF) + extern const char *const sys_errlist[]; +# endif +# else +# undef num_errors +# define num_errors (-1) /* always use "errno=%d" */ +# endif + +#endif + +static char * plp_Errormsg ( int err ) +{ + char *cp; + +#if defined(HAVE_STRERROR) + cp = (void *)strerror(err); +#else +# if defined(HAVE_SYS_ERRLIST) + if (err >= 0 && err < num_errors) { + cp = (void *)sys_errlist[err]; + } else +# endif + { + static char msgbuf[32]; /* holds "errno=%d". */ + /* SAFE use of sprintf */ + (void) sprintf (msgbuf, "errno=%d", err); + cp = msgbuf; + } +#endif + return (cp); +} + +#if defined(TEST) +#include +int main( void ) +{ + char buffer[128]; + char *t; + char *test1 = "01234"; + errno = 1; + plp_snprintf( buffer, sizeof(buffer), (t="errno '%m'")); printf( "%s = '%s'\n", t, buffer ); + plp_snprintf( buffer, sizeof(buffer), (t = "%s"), test1 ); printf( "%s = '%s'\n", t, buffer ); + plp_snprintf( buffer, sizeof(buffer), (t = "%12s"), test1 ); printf( "%s = '%s'\n", t, buffer ); + plp_snprintf( buffer, sizeof(buffer), (t = "%-12s"), test1 ); printf( "%s = '%s'\n", t, buffer ); + plp_snprintf( buffer, sizeof(buffer), (t = "%12.2s"), test1 ); printf( "%s = '%s'\n", t, buffer ); + plp_snprintf( buffer, sizeof(buffer), (t = "%-12.2s"), test1 ); printf( "%s = '%s'\n", t, buffer ); + plp_snprintf( buffer, sizeof(buffer), (t = "%g"), 1.25 ); printf( "%s = '%s'\n", t, buffer ); + plp_snprintf( buffer, sizeof(buffer), (t = "%g"), 1.2345 ); printf( "%s = '%s'\n", t, buffer ); + plp_snprintf( buffer, sizeof(buffer), (t = "%12g"), 1.25 ); printf( "%s = '%s'\n", t, buffer ); + plp_snprintf( buffer, sizeof(buffer), (t = "%12.2g"), 1.25 ); printf( "%s = '%s'\n", t, buffer ); + plp_snprintf( buffer, sizeof(buffer), (t = "%0*d"), 6, 1 ); printf( "%s = '%s'\n", t, buffer ); + return(0); +} +#endif + + +#endif /* HAVE_SNPRINTF */ diff --git a/lib/strdup.c b/lib/strdup.c new file mode 100644 index 0000000..62f2976 --- /dev/null +++ b/lib/strdup.c @@ -0,0 +1,38 @@ +/* Copyright (C) 1997 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 Library General Public License as +published by the Free Software Foundation; either version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include + +#include +#include + +#ifndef HAVE_STRDUP + +char * +strdup (const char * s) +{ + char *clone; + size_t size; + + size = strlen (s) + 1; + clone = malloc (size); + memcpy (clone, s, size); + return clone; +} + +#endif /* !HAVE_STRDUP */ diff --git a/lib/strndup.c b/lib/strndup.c new file mode 100644 index 0000000..b02355e --- /dev/null +++ b/lib/strndup.c @@ -0,0 +1,39 @@ +/* Copyright (C) 1997 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 Library General Public License as +published by the Free Software Foundation; either version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include + +#ifndef HAVE_STRNDUP + +#include +#include + +#include + +char * +strndup (const char * s, size_t n) +{ + char *clone; + + clone = malloc (n + 1); + strncpy (clone, s, n); + clone[n] = '\0'; + return clone; +} + +#endif /* !HAVE_STRNDUP */ diff --git a/lib/strsep.c b/lib/strsep.c new file mode 100644 index 0000000..c3e05e3 --- /dev/null +++ b/lib/strsep.c @@ -0,0 +1,49 @@ +/* Copyright (C) 1992, 1993, 1996 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 Library General Public License as +published by the Free Software Foundation; either version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include + +#include + +#ifndef HAVE_STRSEP + +char * +strsep (char **stringp, const char *delim) +{ + char *begin, *end; + + begin = *stringp; + if (! begin || *begin == '\0') + return NULL; + + /* Find the end of the token. */ + end = strpbrk (begin, delim); + if (end) + { + /* Terminate the token and set *STRINGP past NUL character. */ + *end++ = '\0'; + *stringp = end; + } + else + /* No more delimiters; this is the last token. */ + *stringp = NULL; + + return begin; +} + +#endif /* !HAVE_STRSEP */ diff --git a/lib/usleep.c b/lib/usleep.c new file mode 100644 index 0000000..4f63df4 --- /dev/null +++ b/lib/usleep.c @@ -0,0 +1,60 @@ +/* Copyright (C) 1992 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 Library General Public License as +published by the Free Software Foundation; either version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include + +#ifndef HAVE_USLEEP + +#include +#ifdef HAVE_SYS_TIME_H +# include +#endif + +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#ifdef apollo +# include +# include + static time_$clock_t DomainTime100mS = + { + 0, 100000/4 + }; + static status_$t DomainStatus; +#endif + +/* Sleep USECONDS microseconds, or until a previously set timer goes off. */ +unsigned int +usleep (unsigned int useconds) +{ +#ifdef apollo + /* The usleep function does not work under the SYS5.3 environment. + Use the Domain/OS time_$wait call instead. */ + time_$wait (time_$relative, DomainTime100mS, &DomainStatus); +#else + struct timeval delay; + + delay.tv_sec = 0; + delay.tv_usec = useconds; + select (0, 0, 0, 0, &delay); + return 0; +#endif +} + +#endif /* !HAVE_USLEEP */ diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..cc8783e --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,36 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Last modified: 1994-03-25 +# Public domain + +errstatus=0 + +for file in ${1+"$@"} ; do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d in ${1+"$@"} ; do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$? + fi + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/sane-frontend.NEWS b/sane-frontend.NEWS new file mode 100644 index 0000000..fb7a75f --- /dev/null +++ b/sane-frontend.NEWS @@ -0,0 +1,11 @@ +The SANE-Package has been split into two packages: +SANE (backends) and SANE-FRONTENDS. + +This is an early version of SANE-FRONTENDS. + +If you experience any problems please write +to the sane mailing list or contact: + +Oliver Rauch + + diff --git a/sane.INSTALL b/sane.INSTALL new file mode 100644 index 0000000..8f10389 --- /dev/null +++ b/sane.INSTALL @@ -0,0 +1,21 @@ + +How to configure, build, and install SANE-FRONTENDS. + +Quick install: +============== + +./configure +make +make install + + +- If you get an error message that libsane-dll.so.1 or libsane-so.1 is not found, you have to + tell your system where the SANE-libraries are installed. + - On some systems the library directory "/usr/local/lib" is not searched by the + systems dynamic library loader. If SANE is installed in "/usr/local/..." + you have to tell your systems dynamic library loader to search in "/usr/local/lib". + For linux: add the path "/usr/local/lib" to /etc/ld.so.conf and call ldconfig (as root). + - For sane-1.0.1 you have to add a line with the path to the SANE libraries + (normally /usr/local/lib/sane) to /etc/ld.so.conf and call ldconfig (as root). + For sane-1.0.2 (and later versions) the path to the SANE libs MUST NOT be listed + in /etc/ld.so.conf diff --git a/sane.PROBLEMS b/sane.PROBLEMS new file mode 100644 index 0000000..e0bdebe --- /dev/null +++ b/sane.PROBLEMS @@ -0,0 +1,4 @@ +- xscanimage/xcam crashes X server on Linux/Alpha + Older versions of the TGA X server (such as version 3.1.2) are known + to fail when creating shared images of certain sizes. This can be + avoided by invoking xscanimage and xcam with option --no-shm. diff --git a/sanei/Makefile.in b/sanei/Makefile.in new file mode 100644 index 0000000..d13a25b --- /dev/null +++ b/sanei/Makefile.in @@ -0,0 +1,76 @@ +SHELL = /bin/sh + +VPATH = @srcdir@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = .. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +configdir = ${sysconfdir}/sane.d +sanedatadir = ${datadir}/sane + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +DEFS = @DEFS@ + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +MCOMP = --mode=compile +MLINK = --mode=link + +@SET_MAKE@ + +LIBSANEI_OBJS = sanei_init_debug.o \ + sanei_wire.o sanei_codec_ascii.o sanei_codec_bin.o \ + sanei_save_values.o sanei_load_values.o + +LIBSANEI_LTOBJS = sanei_init_debug.lo \ + sanei_wire.lo sanei_codec_ascii.lo sanei_codec_bin.lo \ + sanei_save_values.lo sanei_load_values.lo + +TARGETS = libsanei.a + +.SUFFIXES: +.SUFFIXES: .c .o +.c.o: + $(COMPILE) $< + @test -f $@ || $(COMPILE) $< + +all: $(TARGETS) + +libsanei.a: $(LIBSANEI_OBJS) + ar r $@ $(LIBSANEI_OBJS) + +install: + +depend: + makedepend -I. -I../include *.c + +clean: + rm -f *.out *.o *.lo *~ *.a *.bak $(OBJS) + rm -rf .libs + +distclean: clean + rm -f Makefile + +.PHONY: all install check depend clean distclean diff --git a/sanei/sanei_codec_ascii.c b/sanei/sanei_codec_ascii.c new file mode 100644 index 0000000..220d0f4 --- /dev/null +++ b/sanei/sanei_codec_ascii.c @@ -0,0 +1,345 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +#include "sane/config.h" + +#include +#include +#include +#include + +#include +#include "../include/sane/sanei_wire.h" +#include "../include/sane/sanei_codec_ascii.h" + +static const char *hexdigit = "0123456789abcdef"; + +static void +skip_ws (Wire *w) +{ + while (1) + { + sanei_w_space (w, 1); + if (w->status != 0) + return; + + if (!isspace (*w->buffer.curr)) + return; + + ++w->buffer.curr; + } +} + +static unsigned +get_digit (Wire *w) +{ + unsigned digit; + + sanei_w_space (w, 1); + digit = tolower(*w->buffer.curr++) - '0'; + if (digit > 9) + digit -= 'a' - ('9' + 1); + if (digit > 0xf) + { + w->status = EINVAL; + return 0; + } + return digit; +} + +static SANE_Byte +get_byte (Wire *w) +{ + return get_digit (w) << 4 | get_digit (w); +} + +static void +ascii_w_byte (Wire *w, void *v) +{ + SANE_Byte *b = v; + + switch (w->direction) + { + case WIRE_ENCODE: + sanei_w_space (w, 3); + *w->buffer.curr++ = hexdigit[(*b >> 4) & 0x0f]; + *w->buffer.curr++ = hexdigit[(*b >> 0) & 0x0f]; + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + skip_ws (w); + *b = get_byte (w); + break; + + case WIRE_FREE: + break; + } +} + +static void +ascii_w_char (Wire *w, void *v) +{ + SANE_Char *c = v; + + switch (w->direction) + { + case WIRE_ENCODE: + sanei_w_space (w, 5); + *w->buffer.curr++ = '\''; + if (*c == '\'' || *c == '\\') + *w->buffer.curr++ = '\\'; + *w->buffer.curr++ = *c; + *w->buffer.curr++ = '\''; + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + sanei_w_space (w, 4); + if (*w->buffer.curr++ != '\'') + { + w->status = EINVAL; + return; + } + *c = *w->buffer.curr++; + if (*c == '\\') + { + sanei_w_space (w, 2); + *c = *w->buffer.curr++; + } + if (*w->buffer.curr++ != '\'') + { + w->status = EINVAL; + return; + } + break; + + case WIRE_FREE: + break; + } +} + +static void +ascii_w_string (Wire *w, void *v) +{ + size_t len, alloced_len; + SANE_String *s = v; + char * str, ch; + int done; + + switch (w->direction) + { + case WIRE_ENCODE: + if (*s) + { + sanei_w_space (w, 1); + *w->buffer.curr++ = '"'; + str = *s; + while ((ch = *str++)) + { + sanei_w_space (w, 2); + if (ch == '"' || ch == '\\') + *w->buffer.curr++ = '\\'; + *w->buffer.curr++ = ch; + } + *w->buffer.curr++ = '"'; + } + else + { + sanei_w_space (w, 5); + *w->buffer.curr++ = '('; + *w->buffer.curr++ = 'n'; + *w->buffer.curr++ = 'i'; + *w->buffer.curr++ = 'l'; + *w->buffer.curr++ = ')'; + } + sanei_w_space (w, 1); + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + skip_ws (w); + sanei_w_space (w, 1); + ch = *w->buffer.curr++; + if (ch == '"') + { + alloced_len = len = 0; + str = 0; + done = 0; + do + { + sanei_w_space (w, 1); + if (w->status != 0) + return; + + ch = *w->buffer.curr++; + if (ch == '"') + done = 1; + + if (ch == '\\') + { + sanei_w_space (w, 1); + ch = *w->buffer.curr++; + } + + if (len >= alloced_len) + { + alloced_len += 1024; + if (!str) + str = malloc (alloced_len); + else + str = realloc (str, alloced_len); + + if (str == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return; + } + } + str[len++] = ch; + } + while (!done); + + str[len - 1] = '\0'; + *s = realloc (str, len); + + if (*s == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return; + } + } + else if (ch == '(') + { + sanei_w_space (w, 4); + if ( *w->buffer.curr++ != 'n' + || *w->buffer.curr++ != 'i' + || *w->buffer.curr++ != 'l' + || *w->buffer.curr++ != ')') + { + w->status = EINVAL; + return; + } + *s = 0; + } + else + { + w->status = EINVAL; + return; + } + break; + + case WIRE_FREE: + if (*s) + free (*s); + break; + } +} + +static void +ascii_w_word (Wire *w, void *v) +{ + SANE_Word val, *word = v; + int i, is_negative = 0; + char buf[16]; + + switch (w->direction) + { + case WIRE_ENCODE: + val = *word; + i = sizeof (buf) - 1; + if (val < 0) + { + is_negative = 1; + val = -val; + } + do + { + buf[i--] = '0' + (val % 10); + val /= 10; + } + while (val); + if (is_negative) + buf[i--] = '-'; + + sanei_w_space (w, sizeof (buf) - i); + memcpy (w->buffer.curr, buf + i + 1, sizeof (buf) - i - 1); + w->buffer.curr += sizeof (buf) - i - 1; + *w->buffer.curr++ = '\n'; + break; + + case WIRE_DECODE: + skip_ws (w); + val = 0; + sanei_w_space (w, 1); + if (*w->buffer.curr == '-') + { + is_negative = 1; + ++w->buffer.curr; + } + while (1) + { + sanei_w_space (w, 1); + if (w->status != 0) + return; + + if (!isdigit (*w->buffer.curr)) + break; + + val = 10*val + (*w->buffer.curr++ - '0'); + } + *word = is_negative ? -val : val; + break; + + case WIRE_FREE: + break; + } +} + +void +sanei_codec_ascii_init (Wire *w) +{ + w->codec.w_byte = ascii_w_byte; + w->codec.w_char = ascii_w_char; + w->codec.w_word = ascii_w_word; + w->codec.w_string = ascii_w_string; +} diff --git a/sanei/sanei_codec_bin.c b/sanei/sanei_codec_bin.c new file mode 100644 index 0000000..7ad77a3 --- /dev/null +++ b/sanei/sanei_codec_bin.c @@ -0,0 +1,128 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +#include "sane/config.h" + +#include +#include +#include + +#include +#include "../include/sane/sanei_wire.h" +#include "../include/sane/sanei_codec_bin.h" + +static void +bin_w_byte (Wire *w, void *v) +{ + SANE_Byte *b = v; + + sanei_w_space (w, 1); + switch (w->direction) + { + case WIRE_ENCODE: + *w->buffer.curr++ = *b; + break; + + case WIRE_DECODE: + *b = *w->buffer.curr++; + break; + + case WIRE_FREE: + break; + } +} + +static void +bin_w_string (Wire *w, void *v) +{ + SANE_Word len; + SANE_String *s = v; + + if (w->direction == WIRE_ENCODE) + { + len = 0; + if (*s) + len = strlen (*s) + 1; + } + sanei_w_array (w, &len, v, w->codec.w_byte, 1); + if (!len && w->direction == WIRE_DECODE) + *s = 0; +} + +static void +bin_w_word (Wire *w, void *v) +{ + SANE_Word val, *word = v; + + sanei_w_space (w, 4); + switch (w->direction) + { + case WIRE_ENCODE: + val = *word; + /* store in bigendian byte-order: */ + w->buffer.curr[0] = (val >> 24) & 0xff; + w->buffer.curr[1] = (val >> 16) & 0xff; + w->buffer.curr[2] = (val >> 8) & 0xff; + w->buffer.curr[3] = (val >> 0) & 0xff; + w->buffer.curr += 4; + break; + + case WIRE_DECODE: + val = ( ((w->buffer.curr[0] & 0xff) << 24) + | ((w->buffer.curr[1] & 0xff) << 16) + | ((w->buffer.curr[2] & 0xff) << 8) + | ((w->buffer.curr[3] & 0xff) << 0)); + *word = val; + w->buffer.curr += 4; + break; + + case WIRE_FREE: + break; + } +} + +void +sanei_codec_bin_init (Wire *w) +{ + w->codec.w_byte = bin_w_byte; + w->codec.w_char = bin_w_byte; + w->codec.w_word = bin_w_word; + w->codec.w_string = bin_w_string; +} diff --git a/sanei/sanei_init_debug.c b/sanei/sanei_init_debug.c new file mode 100644 index 0000000..cf2ce8c --- /dev/null +++ b/sanei/sanei_init_debug.c @@ -0,0 +1,133 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1996, 1997 David Mosberger-Tang and Andreas Beck + This file is part of the SANE package. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +#include "sane/config.h" + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#ifdef HAVE_OS2_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include + +#ifdef HAVE_OS2_H +# define INCL_DOS +# include +#endif + +#define BACKEND_NAME sanei_debug +#include "../include/sane/sanei_debug.h" + +void +sanei_init_debug (const char * backend, int * var) +{ + char ch, buf[256] = "SANE_DEBUG_"; + const char * val; + unsigned int i; + + *var = 0; + + for (i = 11; (ch = backend[i - 11]) != 0; ++i) + { + if (i >= sizeof (buf) - 1) + break; + buf[i] = toupper(ch); + } + buf[i] = '\0'; + + val = getenv (buf); + + if (!val) + return; + + *var = atoi (val); + + DBG (0, "Setting debug level of %s to %d.\n", backend, *var); +} + +void +sanei_debug_msg + (int level, int max_level, const char *be, const char *fmt, va_list ap) +{ + char *msg; + + if (max_level >= level) + { + if ( 1 == isfdtype(fileno(stderr), S_IFSOCK) ) + { + msg = (char *)malloc (sizeof(char) * (strlen(be) + strlen(fmt) + 4)); + if (msg == NULL) + { + syslog (LOG_DEBUG, "[sanei_debug] malloc() failed\n"); + vsyslog (LOG_DEBUG, fmt, ap); + } + else + { + sprintf (msg, "[%s] %s", be, fmt); + vsyslog(LOG_DEBUG, msg, ap); + free (msg); + } + } + else + { + fprintf (stderr, "[%s] ", be); + vfprintf (stderr, fmt, ap); + } + + } +} + +#ifdef NDEBUG +void +sanei_debug_ndebug (int level, const char *fmt, ...) +{ + /* this function is never called */ +} +#endif diff --git a/sanei/sanei_load_values.c b/sanei/sanei_load_values.c new file mode 100644 index 0000000..dae2c3c --- /dev/null +++ b/sanei/sanei_load_values.c @@ -0,0 +1,198 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. + + This file implements a routine to restore option values saved to a + file (using sanei_save_values()). This is a bit tricky since + setting an option may change the availability of other options. + The problem is that we don't know the order of the set-value calls + that resulted in the saved set of option values. One solution + might be to simply keep setting all option values until we no + longer get any changes to the option value set. However, that has + the potential for live-lock. Instead, we keep track of what + options caused a SANE_INFO_RELOAD_OPTIONS. For such options, their + value is set exactly once. This guarantees convergence after a + bounded (and usually small) number of iterations. The resulting + value set is guaranteed to be the desired (saved) one as long as + setting an option that affects availability of other options does + not "lose" its value by setting another option. I don't think any + sane backend would do this and since this is SANE, we just proved + that this algorithm works perfectly. */ + +#ifdef _AIX +# include /* MUST come first for AIX! */ +#endif + +#include "sane/config.h" +#include + +#include +#include +#include +#ifdef HAVE_LIBC_H +# include /* NeXTStep/OpenStep */ +#endif + +#include +#include "../include/sane/sanei_wire.h" +#include "../include/sane/sanei_codec_ascii.h" + +#define BITS_PER_LONG (8*sizeof (u_long)) + +#define SET(set, bit) \ + ((set)[(bit)/BITS_PER_LONG] |= (1UL << (bit)%BITS_PER_LONG)) +#define IS_SET(set, bit) \ + (((set)[(bit)/BITS_PER_LONG] & (1UL << (bit)%BITS_PER_LONG)) != 0) + +int +sanei_load_values (int fd, SANE_Handle device) +{ + const SANE_Option_Descriptor *opt; + SANE_Word *word_array; + SANE_String name, str; + u_long *caused_reload; + SANE_Int num_options; + SANE_Status status; + int i, keep_going; + SANE_Word word; + SANE_Int info; + off_t offset; + size_t size; + char *buf; + Wire w; + + offset = lseek (fd, 0, SEEK_CUR); + w.io.fd = fd; + w.io.read = read; + w.io.write = write; + sanei_w_init (&w, sanei_codec_ascii_init); + sanei_w_set_dir (&w, WIRE_DECODE); + keep_going = 0; + + sane_control_option (device, 0, SANE_ACTION_GET_VALUE, &num_options, 0); + size = (num_options + BITS_PER_LONG - 1) / BITS_PER_LONG * sizeof (long); + caused_reload = alloca (size); + memset (caused_reload, 0, size); + + while (1) + { + sanei_w_space (&w, 3); + + if (!w.status) + sanei_w_string (&w, &name); + + if (w.status) + { + if (keep_going) + { + lseek (fd, offset, SEEK_SET); + sanei_w_set_dir (&w, WIRE_DECODE); + keep_going = 0; + continue; + } + return 0; + } + + status = SANE_STATUS_GOOD; + info = 0; + for (i = 1; (opt = sane_get_option_descriptor (device, i)); ++i) + { + if (!opt->name || strcmp (opt->name, name) != 0) + continue; + + if (IS_SET(caused_reload, i)) + continue; + + switch (opt->type) + { + case SANE_TYPE_BOOL: + case SANE_TYPE_INT: + case SANE_TYPE_FIXED: + if (opt->size == sizeof (SANE_Word)) + { + sanei_w_word (&w, &word); + status = sane_control_option (device, i, + SANE_ACTION_SET_VALUE, + &word, &info); + } + else + { + SANE_Int len; + + sanei_w_array (&w, &len, (void **) &word_array, + (WireCodecFunc) sanei_w_word, + sizeof (SANE_Word)); + status = sane_control_option (device, i, + SANE_ACTION_SET_VALUE, + word_array, &info); + w.direction = WIRE_FREE; + sanei_w_array (&w, &len, (void **) &word_array, + (WireCodecFunc) sanei_w_word, + sizeof (SANE_Word)); + w.direction = WIRE_DECODE; + } + break; + + case SANE_TYPE_STRING: + sanei_w_string (&w, &str); + buf = malloc (opt->size); + strncpy (buf, str, opt->size); + buf[opt->size - 1] = '\0'; + sanei_w_free (&w, (WireCodecFunc) sanei_w_string, &str); + + status = sane_control_option (device, i, SANE_ACTION_SET_VALUE, + buf, &info); + break; + + case SANE_TYPE_BUTTON: + case SANE_TYPE_GROUP: + break; + } + break; + } + sanei_w_free (&w, (WireCodecFunc) sanei_w_string, &name); + + if (status == SANE_STATUS_GOOD && (info & SANE_INFO_RELOAD_OPTIONS)) + { + SET (caused_reload, i); + keep_going = 1; + } + } + return 0; +} diff --git a/sanei/sanei_save_values.c b/sanei/sanei_save_values.c new file mode 100644 index 0000000..94e1dea --- /dev/null +++ b/sanei/sanei_save_values.c @@ -0,0 +1,160 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +#include "sane/config.h" + +#include +#include +#include +#ifdef HAVE_LIBC_H +# include /* NeXTStep/OpenStep */ +#endif + +#include +#include "../include/sane/sanei_wire.h" +#include "../include/sane/sanei_codec_ascii.h" + +int +sanei_save_values (int fd, SANE_Handle device) +{ + const SANE_Option_Descriptor *opt; + size_t word_array_size = 0; + SANE_Word *word_array = 0; + size_t str_size = 0; + SANE_String str = 0; + SANE_Word word; + Wire w; + int i; + + w.io.fd = fd; + w.io.read = read; + w.io.write = write; + sanei_w_init (&w, sanei_codec_ascii_init); + sanei_w_set_dir (&w, WIRE_ENCODE); + + for (i = 0; (opt = sane_get_option_descriptor (device, i)); ++i) + { + if ((opt->cap & (SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT)) + != (SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT) + || !opt->name) + /* if we can't query AND set the option, don't bother saving it */ + continue; + + switch (opt->type) + { + case SANE_TYPE_BOOL: + case SANE_TYPE_INT: + case SANE_TYPE_FIXED: + if (opt->size == sizeof (SANE_Word)) + { + if (sane_control_option (device, i, SANE_ACTION_GET_VALUE, + &word, 0) + != SANE_STATUS_GOOD) + continue; + sanei_w_string (&w, (SANE_String *) &opt->name); + sanei_w_word (&w, &word); + } + else + { + SANE_Int len = opt->size / sizeof (SANE_Word); + + if (opt->size > word_array_size) + { + word_array_size = + ((opt->size + 32*sizeof (SANE_Word)) + & ~(32*sizeof (SANE_Word) - 1)); + if (word_array) + word_array = realloc (word_array, word_array_size); + else + word_array = malloc (word_array_size); + + if (word_array == 0) + { + /* Malloc failed, so return an error. */ + w.status = ENOMEM; + return 1; + } + } + if (sane_control_option (device, i, SANE_ACTION_GET_VALUE, + word_array, 0) + != SANE_STATUS_GOOD) + continue; + sanei_w_string (&w, (SANE_String *) &opt->name); + sanei_w_array (&w, &len, (void **) &word_array, + (WireCodecFunc) sanei_w_word, sizeof (SANE_Word)); + } + break; + + case SANE_TYPE_STRING: + if (opt->size > str_size) + { + str_size = (opt->size + 1024) & ~1023; + if (str) + str = realloc (str, str_size); + else + str = malloc (str_size); + + if (str == 0) + { + /* Malloc failed, so return an error. */ + w.status = ENOMEM; + return 1; + } + } + if (sane_control_option (device, i, SANE_ACTION_GET_VALUE, str, 0) + != SANE_STATUS_GOOD) + continue; + sanei_w_string (&w, (SANE_String *) &opt->name); + sanei_w_string (&w, &str); + break; + + case SANE_TYPE_BUTTON: + case SANE_TYPE_GROUP: + break; + } + } + sanei_w_set_dir (&w, WIRE_DECODE); + + if (word_array) + free (word_array); + if (str) + free (str); + return 0; +} diff --git a/sanei/sanei_thread.c b/sanei/sanei_thread.c new file mode 100644 index 0000000..e3245cd --- /dev/null +++ b/sanei/sanei_thread.c @@ -0,0 +1,108 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 2000 Yuri Dario + This file is part of the SANE package. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. +*/ + +#include "sane/config.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_OS2_H +#define INCL_DOSPROCESS +#include +#endif + +#include "../include/sane/sanei_thread.h" + +/* + * starts a new thread or process + * parameters: + * start address of reader function + * arg_list pointer to scanner data structure + * +*/ +int +sanei_thread_begin( void (*start)(void *arg), + void *arg_list) +{ +#ifdef HAVE_OS2_H + return _beginthread( start, NULL, 64*1024, arg_list); +#else + return fork(); +#endif +} + +int +sanei_thread_kill( int pid, int sig) +{ +#ifdef HAVE_OS2_H + return DosKillThread( pid); +#else + return kill( pid, sig); +#endif +} + +int +sanei_thread_waitpid( int pid, int *stat_loc, int options) +{ +#ifdef HAVE_OS2_H + return pid; /* DosWaitThread( (TID*) &pid, DCWW_WAIT);*/ +#else + return waitpid( pid, stat_loc, options); +#endif +} + +int +sanei_thread_wait( int *stat_loc) +{ +#ifdef HAVE_OS2_H + *stat_loc = 0; + return -1; /* return error because I don't know child pid */ +#else + return wait( stat_loc); +#endif +} + diff --git a/sanei/sanei_wire.c b/sanei/sanei_wire.c new file mode 100644 index 0000000..4bbebfe --- /dev/null +++ b/sanei/sanei_wire.c @@ -0,0 +1,441 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. */ + +#include "sane/config.h" + +#include +#include +#include + +#include + +#include +#include "../include/sane/sanei_wire.h" + +void +sanei_w_space (Wire *w, size_t howmuch) +{ + size_t nbytes, left_over; + int fd = w->io.fd; + ssize_t nread, nwritten; + + if (w->buffer.curr + howmuch > w->buffer.end) + { + switch (w->direction) + { + case WIRE_ENCODE: + nbytes = w->buffer.curr - w->buffer.start; + w->buffer.curr = w->buffer.start; + while (nbytes > 0) + { + nwritten = (*w->io.write) (fd, w->buffer.curr, nbytes); + if (nwritten < 0) + { + w->status = errno; + return; + } + w->buffer.curr += nwritten; + nbytes -= nwritten; + } + w->buffer.curr = w->buffer.start; + w->buffer.end = w->buffer.start + w->buffer.size; + break; + + case WIRE_DECODE: + left_over = w->buffer.end - w->buffer.curr; + if (left_over) + memcpy (w->buffer.start, w->buffer.curr, left_over); + w->buffer.curr = w->buffer.start; + w->buffer.end = w->buffer.start + left_over; + + do { + nread = (*w->io.read) (fd, w->buffer.end, + w->buffer.size - left_over); + if (nread <= 0) + { + if (nread == 0) + errno = EINVAL; + w->status = errno; + return; + } + left_over += nread; + w->buffer.end += nread; + } while (left_over < howmuch); + break; + + case WIRE_FREE: + break; + } + } +} + +void +sanei_w_void (Wire *w) +{ +} + +void +sanei_w_array (Wire *w, SANE_Word *len_ptr, void **v, WireCodecFunc w_element, + size_t element_size) +{ + SANE_Word len; + char *val; + int i; + + if (w->direction == WIRE_FREE) + { + free (*v); + return; + } + + if (w->direction == WIRE_ENCODE) + len = *len_ptr; + + sanei_w_word (w, &len); + + if (w->direction == WIRE_DECODE) + { + *len_ptr = len; + if (len) + { + *v = malloc (len * element_size); + if (*v == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return; + } + } + else + *v = 0; + } + + val = *v; + for (i = 0; i < len; ++i) + { + (*w_element) (w, val); + val += element_size; + } +} + +void +sanei_w_ptr (Wire *w, void **v, WireCodecFunc w_value, size_t value_size) +{ + SANE_Word is_null; + + if (w->direction == WIRE_FREE) + { + if (*v) + free (*v); + return; + } + if (w->direction == WIRE_ENCODE) + is_null = (*v == 0); + + sanei_w_word (w, &is_null); + + if (!is_null) + { + if (w->direction == WIRE_DECODE) + { + *v = malloc (value_size); + if (*v == 0) + { + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + return; + } + } + (*w_value) (w, *v); + } + else if (w->direction == WIRE_DECODE) + *v = 0; +} + +void +sanei_w_byte (Wire *w, SANE_Byte *v) +{ + (*w->codec.w_byte) (w, v); +} + +void +sanei_w_char (Wire *w, SANE_Char *v) +{ + (*w->codec.w_char) (w, v); +} + +void +sanei_w_word (Wire *w, SANE_Word *v) +{ + (*w->codec.w_word) (w, v); +} + +void +sanei_w_string (Wire *w, SANE_String *v) +{ + (*w->codec.w_string) (w, v); +} + +void +sanei_w_status (Wire *w, SANE_Status *v) +{ + SANE_Word word = *v; + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; +} + +void +sanei_w_bool (Wire *w, SANE_Bool *v) +{ + SANE_Word word = *v; + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; +} + +void +sanei_w_constraint_type (Wire *w, SANE_Constraint_Type *v) +{ + SANE_Word word = *v; + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; +} + +void +sanei_w_value_type (Wire *w, SANE_Value_Type *v) +{ + SANE_Word word = *v; + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; +} + +void +sanei_w_unit (Wire *w, SANE_Unit *v) +{ + SANE_Word word = *v; + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; +} + +void +sanei_w_action (Wire *w, SANE_Action *v) +{ + SANE_Word word = *v; + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; +} + +void +sanei_w_frame (Wire *w, SANE_Frame *v) +{ + SANE_Word word = *v; + + sanei_w_word (w, &word); + if (w->direction == WIRE_DECODE) + *v = word; +} + +void +sanei_w_range (Wire *w, SANE_Range *v) +{ + sanei_w_word (w, &v->min); + sanei_w_word (w, &v->max); + sanei_w_word (w, &v->quant); +} + +void +sanei_w_device (Wire *w, SANE_Device *v) +{ + sanei_w_string (w, (SANE_String *) &v->name); + sanei_w_string (w, (SANE_String *) &v->vendor); + sanei_w_string (w, (SANE_String *) &v->model); + sanei_w_string (w, (SANE_String *) &v->type); +} + +void +sanei_w_device_ptr (Wire *w, SANE_Device **v) +{ + sanei_w_ptr (w, (void **) v, + (WireCodecFunc) sanei_w_device, sizeof (**v)); +} + +void +sanei_w_option_descriptor (Wire *w, SANE_Option_Descriptor *v) +{ + SANE_Word len; + + sanei_w_string (w, (SANE_String *) &v->name); + sanei_w_string (w, (SANE_String *) &v->title); + sanei_w_string (w, (SANE_String *) &v->desc); + sanei_w_value_type (w, &v->type); + sanei_w_unit (w, &v->unit); + sanei_w_word (w, &v->size); + sanei_w_word (w, &v->cap); + sanei_w_constraint_type (w, &v->constraint_type); + switch (v->constraint_type) + { + case SANE_CONSTRAINT_NONE: + break; + + case SANE_CONSTRAINT_RANGE: + sanei_w_ptr (w, (void **) &v->constraint.range, + (WireCodecFunc) sanei_w_range, sizeof (SANE_Range)); + break; + + case SANE_CONSTRAINT_WORD_LIST: + if (w->direction == WIRE_ENCODE) + len = v->constraint.word_list[0] + 1; + sanei_w_array (w, &len, (void **) &v->constraint.word_list, + w->codec.w_word, sizeof(SANE_Word)); + break; + + case SANE_CONSTRAINT_STRING_LIST: + if (w->direction == WIRE_ENCODE) + { + for (len = 0; v->constraint.string_list[len]; ++len); + ++len; /* send NULL string, too */ + } + sanei_w_array (w, &len, (void **) &v->constraint.string_list, + w->codec.w_string, sizeof(SANE_String)); + break; + } +} + +void +sanei_w_option_descriptor_ptr (Wire *w, SANE_Option_Descriptor **v) +{ + sanei_w_ptr (w, (void **) v, + (WireCodecFunc) sanei_w_option_descriptor, sizeof (**v)); +} + +void +sanei_w_parameters (Wire *w, SANE_Parameters *v) +{ + sanei_w_frame (w, &v->format); + sanei_w_bool (w, &v->last_frame); + sanei_w_word (w, &v->bytes_per_line); + sanei_w_word (w, &v->pixels_per_line); + sanei_w_word (w, &v->lines); + sanei_w_word (w, &v->depth); +} + +static void +flush (Wire *w) +{ + if (w->direction == WIRE_ENCODE) + sanei_w_space (w, w->buffer.size + 1); + else if (w->direction == WIRE_DECODE) + w->buffer.curr = w->buffer.end = w->buffer.start; +} + +void +sanei_w_set_dir (Wire *w, WireDirection dir) +{ + flush (w); + w->direction = dir; + flush (w); +} + +void +sanei_w_call (Wire *w, + SANE_Word procnum, + WireCodecFunc w_arg, void *arg, + WireCodecFunc w_reply, void *reply) +{ + w->status = 0; + sanei_w_set_dir (w, WIRE_ENCODE); + + sanei_w_word (w, &procnum); + (*w_arg) (w, arg); + + if (w->status == 0) + { + sanei_w_set_dir (w, WIRE_DECODE); + (*w_reply) (w, reply); + } +} + +void +sanei_w_reply (Wire *w, WireCodecFunc w_reply, void *reply) +{ + w->status = 0; + sanei_w_set_dir (w, WIRE_ENCODE); + (*w_reply) (w, reply); + flush (w); +} + +void +sanei_w_free (Wire *w, WireCodecFunc w_reply, void *reply) +{ + WireDirection saved_dir = w->direction; + + w->direction = WIRE_FREE; + (*w_reply) (w, reply); + w->direction = saved_dir; +} + +void +sanei_w_init (Wire *w, void (*codec_init_func)(Wire *)) +{ + w->status = 0; + w->direction = WIRE_ENCODE; + w->buffer.size = 8192; + w->buffer.start = malloc (w->buffer.size); + + if (w->buffer.start == 0) + /* Malloc failed, so return an error. */ + w->status = ENOMEM; + + w->buffer.curr = w->buffer.start; + w->buffer.end = w->buffer.start + w->buffer.size; + if (codec_init_func != 0) + (*codec_init_func) (w); +} diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..5a8536d --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,89 @@ +SHELL = /bin/sh + +VPATH = @srcdir@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = .. + +sane_prefix = @SANE_PREFIX@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +configdir = ${sysconfdir}/sane.d +sanedatadir = ${datadir}/sane + +MKDIR = $(top_srcdir)/mkinstalldirs +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CC = @CC@ +INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include \ + @INCLUDES@ @GTK_CFLAGS@ +DEFS = @DEFS@ +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +SANE_LIBS = @SANE_LIBS@ +GTK_LIBS = @GTK_LIBS@ +GIMP_LIBS = @GIMP_LIBS@ + +XSCAN = @XSCAN@ +BINPROGS = @BINPROGS@ + +COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(LDFLAGS) -o $@ + +@SET_MAKE@ + +PROGRAMS = $(BINPROGS) +LIBLIB = ../lib/liblib.a +LIBSANEI = ../sanei/libsanei.a + +SCAN_OBJS = stiff.o +XSCAN_OBJS = xscanimage.o progress.o preview.o preferences.o gtkglue.o +XCAM_OBJS = xcam.o preferences.o gtkglue.o + +.c.o: + $(COMPILE) $< + +all: $(PROGRAMS) + +install: $(PROGRAMS) + $(MKDIR) $(bindir) $(datadir) + @for program in $(BINPROGS); do \ + $(INSTALL_PROGRAM) $${program} \ + $(bindir)/$${program}; \ + done + $(INSTALL_DATA) $(srcdir)/sane-style.rc $(datadir)/sane-style.rc + +xscanimage: $(XSCAN_OBJS) $(LIBSANEI) $(LIBLIB) + $(LINK) $(XSCAN_OBJS) $(LIBSANEI) \ + $(LIBLIB) $(GIMP_LIBS) $(GTK_LIBS) $(LIBS) $(SANE_LIBS) + +xcam: $(XCAM_OBJS) $(LIBSANEI) $(LIBLIB) + $(LINK) $(XCAM_OBJS) $(LIBSANEI) \ + $(LIBLIB) $(GTK_LIBS) $(LIBS) $(SANE_LIBS) + +clean: + rm -f *.o *~ .*~ *.bak + rm -rf .libs + +distclean: clean + rm -f Makefile $(PROGRAMS) + +depend: + makedepend $(INCLUDES) *.c + +.PHONY: all install depend clean distclean diff --git a/src/gtkglue.c b/src/gtkglue.c new file mode 100644 index 0000000..7d576a6 --- /dev/null +++ b/src/gtkglue.c @@ -0,0 +1,1399 @@ +/* gtk/SANE-glue -- gtk interfacing routines for SANE + Uses the SANE library. + Copyright (C) 1997 David Mosberger and Tristan Tarrant + + 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. */ + +#ifdef _AIX +# include /* MUST come first for AIX! */ +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* Apollo/DomainOS needs this _before_ sys/stat.h */ +#include + +#include + +#include +#include +#include + +int gsg_message_dialog_active = 0; + +/* forward declarations: */ +static void panel_rebuild (GSGDialog * dialog); + +static const char * +unit_string (SANE_Unit unit) +{ + double d; + + switch (unit) + { + case SANE_UNIT_NONE: return "none"; + case SANE_UNIT_PIXEL: return "pixel"; + case SANE_UNIT_BIT: return "bit"; + case SANE_UNIT_DPI: return "dpi"; + case SANE_UNIT_PERCENT: return "%"; + case SANE_UNIT_MM: + d = preferences.length_unit; + if (d > 9.9 && d < 10.1) + return "cm"; + else if (d > 25.3 && d < 25.5) + return "in"; + return "mm"; + case SANE_UNIT_MICROSECOND: return "\265s"; + } + return 0; +} + +static void +set_tooltip (GtkTooltips *tooltips, GtkWidget *widget, const char *desc) +{ + if (desc && desc[0]) +#ifdef HAVE_GTK_TOOLTIPS_SET_TIPS + /* pre 0.99.4: */ + gtk_tooltips_set_tips (tooltips, widget, (char *) desc); +#else + gtk_tooltips_set_tip (tooltips, widget, desc, 0); +#endif +} + +int +gsg_make_path (size_t buf_size, char *buf, + const char *prog_name, + const char *prefix, const char *dev_name, + const char *postfix) +{ + struct passwd *pw; + size_t len, extra; + int i; + + /* first, make sure ~/.sane exists: */ + pw = getpwuid (getuid ()); + if (!pw) + { + snprintf (buf, buf_size, "Failed to determine home directory: %s.", + strerror (errno)); + gsg_error (buf); + return -1; + } + snprintf (buf, buf_size, "%s/.sane", pw->pw_dir); + mkdir (buf, 0777); /* ensure ~/.sane directory exists */ + + len = strlen (buf); + + if (prog_name) + { + extra = strlen (prog_name); + if (len + extra + 1 >= buf_size) + goto filename_too_long; + + buf[len++] = '/'; + memcpy (buf + len, prog_name, extra); + len += extra; + buf[len] = '\0'; + mkdir (buf, 0777); /* ensure ~/.sane/PROG_NAME directory exists */ + } + if (len >= buf_size) + goto filename_too_long; + + buf[len++] = '/'; + + if (prefix) + { + extra = strlen (prefix); + if (len + extra >= buf_size) + goto filename_too_long; + + memcpy (buf + len, prefix, extra); + len += extra; + } + + if (dev_name) + { + /* Turn devicename into valid filename by replacing slashes by + "+-". A lonely `+' gets translated into "++" so we can tell + it from a substituted slash. */ + + for (i = 0; dev_name[i]; ++i) + { + if (len + 2 >= buf_size) + goto filename_too_long; + + switch (dev_name[i]) + { + case '/': + buf[len++] = '+'; + buf[len++] = '-'; + break; + + case '+': + buf[len++] = '+'; + default: + buf[len++] = dev_name[i]; + break; + } + } + } + + if (postfix) + { + extra = strlen (postfix); + if (len + extra >= buf_size) + goto filename_too_long; + memcpy (buf + len, postfix, extra); + len += extra; + } + if (len >= buf_size) + goto filename_too_long; + + buf[len++] = '\0'; + return 0; + +filename_too_long: + gsg_error ("Filename too long."); + errno = E2BIG; + return -1; +} + +static void +set_option (GSGDialog * dialog, int opt_num, void *val, SANE_Action action) +{ + SANE_Status status; + SANE_Int info; + char buf[256]; + + status = sane_control_option (dialog->dev, opt_num, action, val, &info); + if (status != SANE_STATUS_GOOD) + { + snprintf (buf, sizeof (buf), "Failed to set value of option %s: %s.", + sane_get_option_descriptor (dialog->dev, opt_num)->name, + sane_strstatus (status)); + gsg_error (buf); + return; + } + if (info & SANE_INFO_RELOAD_OPTIONS) + { + panel_rebuild (dialog); + if (dialog->option_reload_callback) + (*dialog->option_reload_callback) (dialog, dialog->option_reload_arg); + } + if ((info & SANE_INFO_RELOAD_PARAMS) && dialog->param_change_callback) + (*dialog->param_change_callback) (dialog, dialog->param_change_arg); +} + +void +gsg_close_dialog_callback (GtkWidget * widget, gpointer data) +{ + gtk_widget_destroy (data); + gsg_message_dialog_active = 0; +} + +void +gsg_message (gchar *title, gchar *message) +{ + GtkWidget *main_vbox, *label; + GtkWidget *button, *message_dialog; + + if (gsg_message_dialog_active) + { + fprintf (stderr, "%s: %s\n", title, message); + return; + } + gsg_message_dialog_active = 1; + message_dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_position (GTK_WINDOW (message_dialog), GTK_WIN_POS_MOUSE); + gtk_window_set_title (GTK_WINDOW (message_dialog), title); + + /* create the main vbox */ + main_vbox = gtk_vbox_new (TRUE, 5); + gtk_container_border_width (GTK_CONTAINER (main_vbox), 5); + gtk_widget_show (main_vbox); + + gtk_container_add (GTK_CONTAINER (message_dialog), main_vbox); + + /* the message */ + label = gtk_label_new (message); + gtk_container_add (GTK_CONTAINER (main_vbox), label); + gtk_widget_show (label); + + /* the confirmation button */ + button = gtk_button_new_with_label ("OK"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gsg_close_dialog_callback, + message_dialog); + gtk_container_add (GTK_CONTAINER (main_vbox), button); + + gtk_widget_show (button); + gtk_widget_show (message_dialog); +} + +void +gsg_error (gchar * error) +{ + gsg_message ("Error", error); +} + +void +gsg_warning (gchar * warning) +{ + gsg_message ("Warning", warning); +} + +static void +get_filename_button_clicked (GtkWidget *w, gpointer data) +{ + int *clicked = data; + *clicked = 1; +} + +int +gsg_get_filename (const char *label, const char *default_name, + size_t max_len, char *filename) +{ + int cancel = 0, ok = 0; + GtkWidget *filesel; + + filesel = gtk_file_selection_new ((char *) label); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button), + "clicked", (GtkSignalFunc) get_filename_button_clicked, + &cancel); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button), + "clicked", (GtkSignalFunc) get_filename_button_clicked, + &ok); + if (default_name) + gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel), + (char *) default_name); + + gtk_widget_show (filesel); + + while (!cancel && !ok) + { + if (!gtk_events_pending ()) + usleep (100000); + gtk_main_iteration (); + } + + if (ok) + { + size_t len, cwd_len; + char *cwd; + + strncpy (filename, + gtk_file_selection_get_filename (GTK_FILE_SELECTION (filesel)), + max_len - 1); + filename[max_len - 1] = '\0'; + + len = strlen (filename); + cwd = alloca (len + 2); + getcwd (cwd, len + 1); + cwd_len = strlen (cwd); + cwd[cwd_len++] = '/'; + cwd[cwd_len] = '\0'; + if (strncmp (filename, cwd, cwd_len) == 0) + memcpy (filename, filename + cwd_len, len - cwd_len + 1); + } + gtk_widget_destroy (filesel); + return cancel ? -1 : 0; +} + +static gint +autobutton_update (GtkWidget * widget, GSGDialogElement * elem) +{ + GSGDialog *dialog = elem->dialog; + int opt_num = elem - dialog->element; + const SANE_Option_Descriptor *opt; + SANE_Status status; + SANE_Word val; + char buf[256]; + + opt = sane_get_option_descriptor (dialog->dev, opt_num); + if (GTK_TOGGLE_BUTTON (widget)->active) + set_option (dialog, opt_num, 0, SANE_ACTION_SET_AUTO); + else + { + status = sane_control_option (dialog->dev, opt_num, + SANE_ACTION_GET_VALUE, &val, 0); + if (status != SANE_STATUS_GOOD) + { + snprintf (buf, sizeof (buf), + "Failed to obtain value of option %s: %s.", + opt->name, sane_strstatus (status)); + gsg_error (buf); + } + set_option (dialog, opt_num, &val, SANE_ACTION_SET_VALUE); + } + return FALSE; +} + +static void +autobutton_new (GtkWidget *parent, GSGDialogElement *elem, + GtkWidget *label, GtkTooltips *tooltips) +{ + GtkWidget *button, *alignment; + + button = gtk_check_button_new (); + gtk_container_border_width (GTK_CONTAINER (button), 0); + gtk_widget_set_usize (button, 20, 20); + gtk_signal_connect (GTK_OBJECT (button), "toggled", + (GtkSignalFunc) autobutton_update, + elem); + set_tooltip (tooltips, button, "Turns on automatic mode."); + + alignment = gtk_alignment_new (0.0, 1.0, 0.5, 0.5); + gtk_container_add (GTK_CONTAINER (alignment), button); + + gtk_box_pack_end (GTK_BOX (parent), label, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (parent), alignment, FALSE, FALSE, 2); + + gtk_widget_show (alignment); + gtk_widget_show (button); +} + +static gint +button_update (GtkWidget * widget, GSGDialogElement * elem) +{ + GSGDialog *dialog = elem->dialog; + int opt_num = elem - dialog->element; + const SANE_Option_Descriptor *opt; + SANE_Word val = SANE_FALSE; + + opt = sane_get_option_descriptor (dialog->dev, opt_num); + if (GTK_TOGGLE_BUTTON (widget)->active) + val = SANE_TRUE; + set_option (dialog, opt_num, &val, SANE_ACTION_SET_VALUE); + return FALSE; +} + +static void +button_new (GtkWidget * parent, const char *name, SANE_Word val, + GSGDialogElement * elem, GtkTooltips *tooltips, const char *desc) +{ + GtkWidget *button; + + button = gtk_check_button_new_with_label ((char *) name); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), val); + gtk_signal_connect (GTK_OBJECT (button), "toggled", + (GtkSignalFunc) button_update, + elem); + gtk_box_pack_start (GTK_BOX (parent), button, FALSE, TRUE, 0); + gtk_widget_show (button); + set_tooltip (tooltips, button, desc); + + elem->widget = button; +} + +static void +scale_update (GtkAdjustment * adj_data, GSGDialogElement * elem) +{ + const SANE_Option_Descriptor *opt; + GSGDialog *dialog = elem->dialog; + SANE_Word val, new_val; + int opt_num; + double d; + + opt_num = elem - dialog->element; + opt = sane_get_option_descriptor (dialog->dev, opt_num); + switch (opt->type) + { + case SANE_TYPE_INT: + val = adj_data->value + 0.5; + break; + + case SANE_TYPE_FIXED: + d = adj_data->value; + if (opt->unit == SANE_UNIT_MM) + d *= preferences.length_unit; + val = SANE_FIX (d); + break; + + default: + fprintf (stderr, "scale_update: unknown type %d\n", opt->type); + return; + } + set_option (dialog, opt_num, &val, SANE_ACTION_SET_VALUE); + sane_control_option (dialog->dev, opt_num, SANE_ACTION_GET_VALUE, &new_val, + 0); + if (new_val != val) + { + val = new_val; + goto value_changed; + } + return; /* value didn't change */ + +value_changed: + switch (opt->type) + { + case SANE_TYPE_INT: + adj_data->value = val; + break; + + case SANE_TYPE_FIXED: + d = SANE_UNFIX (val); + if (opt->unit == SANE_UNIT_MM) + d /= preferences.length_unit; + adj_data->value = d; + break; + + default: + break; + } + /* Let widget know that value changed _again_. This must converge + quickly---otherwise things would get very slow very quickly (as + in "infinite recursion"): */ + gtk_signal_emit_by_name (GTK_OBJECT (adj_data), "value_changed"); + return; +} + +static void +scale_new (GtkWidget * parent, const char *name, gfloat val, + gfloat min, gfloat max, gfloat quant, int automatic, + GSGDialogElement * elem, GtkTooltips *tooltips, const char *desc) +{ + GtkWidget *hbox, *label, *scale; + + hbox = gtk_hbox_new (FALSE, 2); + gtk_container_border_width (GTK_CONTAINER (hbox), 0); + gtk_box_pack_start (GTK_BOX (parent), hbox, FALSE, FALSE, 0); + + label = gtk_label_new ((char *) name); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2); + + elem->data = gtk_adjustment_new (val, min, max, quant, 1.0, 0.0); + scale = gtk_hscale_new (GTK_ADJUSTMENT (elem->data)); + set_tooltip (tooltips, scale, desc); + gtk_widget_set_usize (scale, 200, 0); + + if (automatic) + autobutton_new (hbox, elem, scale, tooltips); + else + gtk_box_pack_end (GTK_BOX (hbox), scale, FALSE, FALSE, 0); + + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_CONTINUOUS); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + if (quant - (int) quant == 0.0) + gtk_scale_set_digits (GTK_SCALE (scale), 0); + else + /* one place behind decimal point */ + gtk_scale_set_digits (GTK_SCALE (scale), 1); + + gtk_signal_connect (elem->data, "value_changed", + (GtkSignalFunc) scale_update, elem); + + gtk_widget_show (label); + gtk_widget_show (scale); + gtk_widget_show (hbox); + + elem->widget = scale; +} + +static void +push_button_callback (GtkWidget * widget, gpointer data) +{ + GSGDialogElement *elem = data; + GSGDialog *dialog = elem->dialog; + int opt_num; + + opt_num = elem - dialog->element; + set_option (dialog, opt_num, 0, SANE_ACTION_SET_VALUE); +} + +static int +option_menu_lookup (GSGMenuItem menu_items[], const char *string) +{ + int i; + + for (i = 0; strcmp (menu_items[i].label, string) != 0; ++i); + return i; +} + +static void +option_menu_callback (GtkWidget * widget, gpointer data) +{ + GSGMenuItem *menu_item = data; + GSGDialogElement *elem = menu_item->elem; + const SANE_Option_Descriptor *opt; + GSGDialog *dialog = elem->dialog; + int opt_num; + double dval; + SANE_Word val; + void *valp = &val; + + opt_num = elem - dialog->element; + opt = sane_get_option_descriptor (dialog->dev, opt_num); + switch (opt->type) + { + case SANE_TYPE_INT: + sscanf (menu_item->label, "%d", &val); + break; + + case SANE_TYPE_FIXED: + sscanf (menu_item->label, "%lg", &dval); + val = SANE_FIX (dval); + break; + + case SANE_TYPE_STRING: + valp = menu_item->label; + break; + + default: + fprintf (stderr, "option_menu_callback: unexpected type %d\n", + opt->type); + break; + } + set_option (dialog, opt_num, valp, SANE_ACTION_SET_VALUE); +} + +static void +option_menu_new (GtkWidget *parent, const char *name, char *str_list[], + const char *val, GSGDialogElement * elem, + GtkTooltips *tooltips, const char *desc) +{ + GtkWidget *hbox, *label, *option_menu, *menu, *item; + GSGMenuItem *menu_items; + int i, num_items; + + hbox = gtk_hbox_new (FALSE, 2); + gtk_container_border_width (GTK_CONTAINER (hbox), 0); + gtk_box_pack_start (GTK_BOX (parent), hbox, FALSE, FALSE, 0); + + label = gtk_label_new ((char *) name); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2); + + for (num_items = 0; str_list[num_items]; ++num_items); + menu_items = malloc (num_items * sizeof (menu_items[0])); + + menu = gtk_menu_new (); + for (i = 0; i < num_items; ++i) + { + item = gtk_menu_item_new_with_label (str_list[i]); + gtk_container_add (GTK_CONTAINER (menu), item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + (GtkSignalFunc) option_menu_callback, + menu_items + i); + + gtk_widget_show (item); + + menu_items[i].label = str_list[i]; + menu_items[i].elem = elem; + menu_items[i].index = i; + } + + option_menu = gtk_option_menu_new (); + gtk_box_pack_end (GTK_BOX (hbox), option_menu, FALSE, FALSE, 2); + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), + option_menu_lookup (menu_items, val)); + set_tooltip (tooltips, option_menu, desc); + + gtk_widget_show (label); + gtk_widget_show (option_menu); + gtk_widget_show (hbox); + + elem->widget = option_menu; + elem->menu_size = num_items; + elem->menu = menu_items; +} + +static void +text_entry_callback (GtkWidget *w, gpointer data) +{ + GSGDialogElement *elem = data; + const SANE_Option_Descriptor *opt; + GSGDialog *dialog = elem->dialog; + gchar *text; + int opt_num; + char *buf; + + opt_num = elem - dialog->element; + opt = sane_get_option_descriptor (dialog->dev, opt_num); + + buf = alloca (opt->size); + buf[0] = '\0'; + + text = gtk_entry_get_text (GTK_ENTRY (elem->widget)); + if (text) + strncpy (buf, text, opt->size); + buf[opt->size - 1] = '\0'; + + set_option (dialog, opt_num, buf, SANE_ACTION_SET_VALUE); + + if (strcmp (buf, text) != 0) + /* the backend modified the option value; update widget: */ + gtk_entry_set_text (GTK_ENTRY (elem->widget), buf); +} + +static void +text_entry_new (GtkWidget * parent, const char *name, const char *val, + GSGDialogElement * elem, + GtkTooltips *tooltips, const char *desc) +{ + GtkWidget *hbox, *text, *label; + + hbox = gtk_hbox_new (FALSE, 2); + gtk_container_border_width (GTK_CONTAINER (hbox), 0); + gtk_box_pack_start (GTK_BOX (parent), hbox, FALSE, FALSE, 0); + + label = gtk_label_new ((char *) name); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2); + + text = gtk_entry_new (); + gtk_entry_set_text (GTK_ENTRY (text), (char *) val); + gtk_box_pack_start (GTK_BOX (hbox), text, FALSE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (text), "changed", + (GtkSignalFunc) text_entry_callback, elem); + set_tooltip (tooltips, text, desc); + + gtk_widget_show (hbox); + gtk_widget_show (label); + gtk_widget_show (text); + + elem->widget = text; +} + +static GtkWidget * +group_new (GtkWidget *parent, const char * title) +{ + GtkWidget * frame, * vbox; + + frame = gtk_frame_new ((char *) title); + gtk_container_border_width (GTK_CONTAINER (frame), 4); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); + gtk_box_pack_start (GTK_BOX (parent), frame, FALSE, FALSE, 0); + + vbox = gtk_vbox_new (FALSE, 4); + gtk_container_border_width (GTK_CONTAINER (vbox), 2); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_widget_show (vbox); + return vbox; +} + +static GtkWidget* +curve_new (GSGDialog *dialog, int optnum) +{ + const SANE_Option_Descriptor * opt; + gfloat fmin, fmax, val, *vector; + SANE_Word *optval, min, max; + GtkWidget *curve, *gamma; + SANE_Status status; + SANE_Handle dev; + int i, optlen; + + gamma = gtk_gamma_curve_new (); + curve = GTK_GAMMA_CURVE (gamma)->curve; + dev = dialog->dev; + + opt = sane_get_option_descriptor (dev, optnum); + optlen = opt->size / sizeof (SANE_Word); + vector = alloca (optlen * (sizeof (vector[0]) + sizeof (optval[0]))); + optval = (SANE_Word *) (vector + optlen); + + min = max = 0; + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + min = opt->constraint.range->min; + max = opt->constraint.range->max; + break; + + case SANE_CONSTRAINT_WORD_LIST: + if (opt->constraint.word_list[0] > 1) + { + min = max = opt->constraint.word_list[1]; + for (i = 2; i < opt->constraint.word_list[0]; ++i) + { + if (opt->constraint.word_list[i] < min) + min = opt->constraint.word_list[i]; + if (opt->constraint.word_list[i] > max) + max = opt->constraint.word_list[i]; + } + } + break; + + default: + break; + } + if (min == max) + { + fprintf (stderr, + "curve_new: warning: option `%s' has no value constraint\n", + opt->name); + fmin = 0; + fmax = 255; + } + else if (opt->type == SANE_TYPE_FIXED) + { + fmin = SANE_UNFIX (min); + fmax = SANE_UNFIX (max); + } + else + { + fmin = min; + fmax = max; + } + gtk_curve_set_range (GTK_CURVE (curve), 0, optlen - 1, fmin, fmax); + + status = sane_control_option (dev, optnum, SANE_ACTION_GET_VALUE, + optval, 0); + if (status == SANE_STATUS_GOOD) + { + for (i = 0; i < optlen; ++i) + { + if (opt->type == SANE_TYPE_FIXED) + val = SANE_UNFIX (optval[i]); + else + val = optval[i]; + vector[i] = val; + } + gtk_curve_set_vector (GTK_CURVE (curve), optlen, vector); + } + else + gtk_widget_set_sensitive (gamma, FALSE); + + return gamma; +} + +static void +vector_new (GSGDialog * dialog, GtkWidget *vbox, int num_vopts, int *vopts) +{ + GtkWidget *notebook, *label, *curve; + const SANE_Option_Descriptor *opt; + int i; + + notebook = gtk_notebook_new (); + gtk_container_border_width (GTK_CONTAINER (notebook), 4); + gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0); + + for (i = 0; i < num_vopts; ++i) + { + opt = sane_get_option_descriptor (dialog->dev, vopts[i]); + + label = gtk_label_new ((char *) opt->title); + vbox = gtk_vbox_new (/* homogeneous */ FALSE, 0); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + gtk_widget_show (vbox); + gtk_widget_show (label); + + curve = curve_new (dialog, vopts[i]); + gtk_container_border_width (GTK_CONTAINER (curve), 4); + gtk_box_pack_start (GTK_BOX (vbox), curve, TRUE, TRUE, 0); + gtk_widget_show (curve); + + dialog->element[vopts[i]].widget = curve; + } + gtk_widget_show (notebook); +} + +static void +panel_destroy (GSGDialog * dialog) +{ + const SANE_Option_Descriptor *opt; + GSGDialogElement *elem; + int i, j; + +#ifdef HAVE_GTK_TOOLTIPS_SET_TIPS + /* pre 0.99.4: */ + gtk_tooltips_unref (dialog->tooltips); +#else + gtk_object_unref (GTK_OBJECT (dialog->tooltips)); +#endif + gtk_widget_destroy (dialog->main_hbox); + + /* free the menu labels of integer/fix-point word-lists: */ + for (i = 0; i < dialog->num_elements; ++i) + { + if (dialog->element[i].menu) + { + opt = sane_get_option_descriptor (dialog->dev, i); + elem = dialog->element + i; + if (opt->type != SANE_TYPE_STRING) + for (j = 0; j < elem->menu_size; ++j) + if (elem->menu[j].label) + { + free (elem->menu[j].label); + elem->menu[j].label = 0; + } + free (elem->menu); + elem->menu = 0; + } + } + memset (dialog->element, 0, + dialog->num_elements*sizeof (dialog->element[0])); +} + +static void +panel_build (GSGDialog * dialog) +{ + GtkWidget *main_hbox, *standard_vbox, *advanced_vbox, *option_vbox; + GtkWidget *parent, *vbox, *button, *label; + const SANE_Option_Descriptor *opt; + SANE_Handle dev = dialog->dev; + double dval, dmin, dmax, dquant; + char *buf, str[16], title[256]; + GSGDialogElement *elem; + SANE_Word quant, val; + SANE_Status status; + SANE_Int num_words; + char **str_list; + int i, j; + int num_vector_opts = 0, *vector_opts; + + main_hbox = gtk_hbox_new (FALSE, 2); + + option_vbox = gtk_vbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (main_hbox), option_vbox, FALSE, FALSE, 0); + gtk_widget_show (option_vbox); + + /* standard options vbox */ + + standard_vbox = gtk_vbox_new (/* homogeneous */ FALSE, 0); + gtk_widget_show (standard_vbox); + gtk_box_pack_start (GTK_BOX (option_vbox), standard_vbox, FALSE, FALSE, 0); + + /* advanced options page */ + + advanced_vbox = gtk_vbox_new (/* homogeneous */ FALSE, 0); + gtk_box_pack_start (GTK_BOX (option_vbox), advanced_vbox, TRUE, TRUE, 0); + + /* use black as foreground: */ + dialog->tooltips = gtk_tooltips_new (); + dialog->tooltips_fg.red = 0; + dialog->tooltips_fg.green = 0; + dialog->tooltips_fg.blue = 0; + /* postit yellow (khaki) as background: */ + gdk_color_alloc (gtk_widget_get_colormap (main_hbox), &dialog->tooltips_fg); + dialog->tooltips_bg.red = 61669; + dialog->tooltips_bg.green = 59113; + dialog->tooltips_bg.blue = 35979; + gdk_color_alloc (gtk_widget_get_colormap (main_hbox), &dialog->tooltips_bg); + gtk_tooltips_set_colors (dialog->tooltips, + &dialog->tooltips_bg, &dialog->tooltips_fg); + gsg_set_tooltips (dialog, preferences.tooltips_enabled); + + gtk_container_add (GTK_CONTAINER (dialog->window), main_hbox); + dialog->main_hbox = main_hbox; + dialog->advanced_vbox = advanced_vbox; + + /* reset well-known options: */ + dialog->well_known.preview = -1; + dialog->well_known.dpi = -1; + dialog->well_known.coord[GSG_TL_X] = -1; + dialog->well_known.coord[GSG_TL_Y] = -1; + dialog->well_known.coord[GSG_BR_X] = -1; + dialog->well_known.coord[GSG_BR_Y] = -1; + + vector_opts = alloca (dialog->num_elements * sizeof (int)); + + parent = standard_vbox; + for (i = 1; i < dialog->num_elements; ++i) + { + opt = sane_get_option_descriptor (dev, i); + if (!SANE_OPTION_IS_ACTIVE (opt->cap)) + continue; + + /* pick up well-known options as we go: */ + if (opt->name) + { + if (strcmp (opt->name, SANE_NAME_PREVIEW) == 0 + && opt->type == SANE_TYPE_BOOL) + { + dialog->well_known.preview = i; + continue; + } + else if (strcmp (opt->name, SANE_NAME_SCAN_RESOLUTION) == 0 + && opt->unit == SANE_UNIT_DPI + && (opt->type == SANE_TYPE_INT + || opt->type == SANE_TYPE_FIXED)) + dialog->well_known.dpi = i; + else if (strcmp (opt->name, SANE_NAME_SCAN_TL_X) == 0) + dialog->well_known.coord[GSG_TL_X] = i; + else if (strcmp (opt->name, SANE_NAME_SCAN_TL_Y) == 0) + dialog->well_known.coord[GSG_TL_Y] = i; + else if (strcmp (opt->name, SANE_NAME_SCAN_BR_X) == 0) + dialog->well_known.coord[GSG_BR_X] = i; + else if (strcmp (opt->name, SANE_NAME_SCAN_BR_Y) == 0) + dialog->well_known.coord[GSG_BR_Y] = i; + } + + elem = dialog->element + i; + elem->dialog = dialog; + + if (opt->unit == SANE_UNIT_NONE) + strncpy (title, opt->title, sizeof (title)); + else + snprintf (title, sizeof (title), + "%s [%s]", opt->title, unit_string (opt->unit)); + + switch (opt->type) + { + case SANE_TYPE_GROUP: + /* group a set of options */ + vbox = standard_vbox; + if (opt->cap & SANE_CAP_ADVANCED) + vbox = advanced_vbox; + parent = group_new (vbox, title); + elem->widget = parent; + break; + + case SANE_TYPE_BOOL: + if ((opt->cap & SANE_CAP_ADVANCED) && !dialog->advanced) + break; + assert (opt->size == sizeof (SANE_Word)); + status = sane_control_option (dialog->dev, i, SANE_ACTION_GET_VALUE, + &val, 0); + if (status != SANE_STATUS_GOOD) + goto get_value_failed; + + button_new (parent, title, val, elem, dialog->tooltips, opt->desc); + gtk_widget_show (parent->parent); + break; + + case SANE_TYPE_INT: + if ((opt->cap & SANE_CAP_ADVANCED) && !dialog->advanced) + break; + if (opt->size != sizeof (SANE_Word)) + { + vector_opts[num_vector_opts++] = i; + break; + } + status = sane_control_option (dialog->dev, i, SANE_ACTION_GET_VALUE, + &val, 0); + if (status != SANE_STATUS_GOOD) + goto get_value_failed; + + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + /* use a scale */ + quant = opt->constraint.range->quant; + if (quant == 0) + quant = 1; + scale_new (parent, title, val, + opt->constraint.range->min, + opt->constraint.range->max, quant, + (opt->cap & SANE_CAP_AUTOMATIC), elem, + dialog->tooltips, opt->desc); + gtk_widget_show (parent->parent); + break; + + case SANE_CONSTRAINT_WORD_LIST: + /* use a "list-selection" widget */ + num_words = opt->constraint.word_list[0]; + str_list = malloc ((num_words + 1) * sizeof (str_list[0])); + for (j = 0; j < num_words; ++j) + { + sprintf (str, "%d", opt->constraint.word_list[j + 1]); + str_list[j] = strdup (str); + } + str_list[j] = 0; + sprintf (str, "%d", val); + option_menu_new (parent, title, str_list, str, elem, + dialog->tooltips, opt->desc); + free (str_list); + gtk_widget_show (parent->parent); + break; + + default: + fprintf (stderr, "panel_build: unknown constraint %d!\n", + opt->constraint_type); + break; + } + break; + + case SANE_TYPE_FIXED: + if ((opt->cap & SANE_CAP_ADVANCED) && !dialog->advanced) + break; + if (opt->size != sizeof (SANE_Word)) + { + vector_opts[num_vector_opts++] = i; + break; + } + status = sane_control_option (dialog->dev, i, SANE_ACTION_GET_VALUE, + &val, 0); + if (status != SANE_STATUS_GOOD) + goto get_value_failed; + + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + /* use a scale */ + quant = opt->constraint.range->quant; + if (quant == 0) + quant = 1; + dval = SANE_UNFIX (val); + dmin = SANE_UNFIX (opt->constraint.range->min); + dmax = SANE_UNFIX (opt->constraint.range->max); + dquant = SANE_UNFIX (quant); + if (opt->unit == SANE_UNIT_MM) + { + dval /= preferences.length_unit; + dmin /= preferences.length_unit; + dmax /= preferences.length_unit; + dquant /= preferences.length_unit; + } + scale_new (parent, title, dval, dmin, dmax, dquant, + (opt->cap & SANE_CAP_AUTOMATIC), elem, + dialog->tooltips, opt->desc); + gtk_widget_show (parent->parent); + break; + + case SANE_CONSTRAINT_WORD_LIST: + /* use a "list-selection" widget */ + num_words = opt->constraint.word_list[0]; + str_list = malloc ((num_words + 1) * sizeof (str_list[0])); + for (j = 0; j < num_words; ++j) + { + sprintf (str, "%g", + SANE_UNFIX (opt->constraint.word_list[j + 1])); + str_list[j] = strdup (str); + } + str_list[j] = 0; + sprintf (str, "%g", SANE_UNFIX (val)); + option_menu_new (parent, title, str_list, str, elem, + dialog->tooltips, opt->desc); + free (str_list); + gtk_widget_show (parent->parent); + break; + + default: + fprintf (stderr, "panel_build: unknown constraint %d!\n", + opt->constraint_type); + break; + } + break; + + case SANE_TYPE_STRING: + if ((opt->cap & SANE_CAP_ADVANCED) && !dialog->advanced) + break; + buf = malloc (opt->size); + status = sane_control_option (dialog->dev, i, SANE_ACTION_GET_VALUE, + buf, 0); + if (status != SANE_STATUS_GOOD) + { + free (buf); + goto get_value_failed; + } + + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_STRING_LIST: + /* use a "list-selection" widget */ + option_menu_new (parent, title, + (char **) opt->constraint.string_list, buf, + elem, dialog->tooltips, opt->desc); + gtk_widget_show (parent->parent); + break; + + case SANE_CONSTRAINT_NONE: + text_entry_new (parent, title, buf, elem, + dialog->tooltips, opt->desc); + gtk_widget_show (parent->parent); + break; + + default: + fprintf (stderr, "panel_build: unknown constraint %d!\n", + opt->constraint_type); + break; + } + free (buf); + break; + + case SANE_TYPE_BUTTON: + if ((opt->cap & SANE_CAP_ADVANCED) && !dialog->advanced) + break; + button = gtk_button_new (); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) push_button_callback, elem); + set_tooltip (dialog->tooltips, button, opt->desc); + + label = gtk_label_new (title); + gtk_container_add (GTK_CONTAINER (button), label); + + gtk_box_pack_start (GTK_BOX (parent), button, FALSE, TRUE, 0); + + gtk_widget_show (label); + gtk_widget_show (button); + + elem->widget = button; + gtk_widget_show (parent->parent); + break; + + default: + fprintf (stderr, "panel_build: Unknown type %d\n", opt->type); + break; + } + continue; + + get_value_failed: + { + char msg[256]; + + sprintf (msg, "Failed to obtain value of option %s: %s.", + opt->name, sane_strstatus (status)); + gsg_error (msg); + } + } + + /* now add in vector editor, if necessary: */ + + if (num_vector_opts) + vector_new (dialog, main_hbox, num_vector_opts, vector_opts); + + if (dialog->advanced) + gtk_widget_show (dialog->advanced_vbox); + else + gtk_widget_hide (dialog->advanced_vbox); + gtk_widget_show (main_hbox); +} + +/* When an setting an option changes the dialog, everything may + change: the option titles, the activity-status of the option, its + constraints or what not. Thus, rather than trying to be clever in + detecting what exactly changed, we use a brute-force method of + rebuilding the entire dialog. */ +static void +panel_rebuild (GSGDialog * dialog) +{ + panel_destroy (dialog); + panel_build (dialog); +} + +GSGDialog * +gsg_create_dialog (GtkWidget * window, const char *device_name, + GSGCallback option_reload_callback, void *option_reload_arg, + GSGCallback param_change_callback, void *param_change_arg) +{ + SANE_Int num_elements; + GSGDialog *dialog; + SANE_Status status; + SANE_Handle dev; + char buf[256]; + + status = sane_open (device_name, &dev); + if (status != SANE_STATUS_GOOD) + { + sprintf (buf, "Failed to open device `%s': %s.", + device_name, sane_strstatus (status)); + gsg_error (buf); + return 0; + } + + if (sane_control_option (dev, 0, SANE_ACTION_GET_VALUE, &num_elements, 0) + != SANE_STATUS_GOOD) + { + gsg_error ("Error obtaining option count."); + sane_close (dev); + return 0; + } + + dialog = malloc (sizeof (*dialog)); + memset (dialog, 0, sizeof (*dialog)); + + dialog->window = window; + dialog->dev = dev; + dialog->dev_name = strdup (device_name); + dialog->num_elements = num_elements; + dialog->option_reload_callback = option_reload_callback; + dialog->option_reload_arg = option_reload_arg; + dialog->param_change_callback = param_change_callback; + dialog->param_change_arg = param_change_arg; + dialog->advanced = preferences.advanced; + + dialog->element = malloc (num_elements * sizeof (dialog->element[0])); + memset (dialog->element, 0, num_elements * sizeof (dialog->element[0])); + + panel_build (dialog); + return dialog; +} + +void +gsg_refresh_dialog (GSGDialog *dialog) +{ + panel_rebuild (dialog); + if (dialog->param_change_callback) + (*dialog->param_change_callback) (dialog, dialog->param_change_arg); +} + +void +gsg_update_scan_window (GSGDialog *dialog) +{ + const SANE_Option_Descriptor *opt; + double old_val, new_val; + GSGDialogElement *elem; + SANE_Status status; + SANE_Word word; + int i, optnum; + char str[64]; + + for (i = 0; i < 4; ++i) + if (dialog->well_known.coord[i] > 0) + { + optnum = dialog->well_known.coord[i]; + elem = dialog->element + optnum; + opt = sane_get_option_descriptor (dialog->dev, optnum); + + status = sane_control_option (dialog->dev, optnum, + SANE_ACTION_GET_VALUE, + &word, 0); + if (status != SANE_STATUS_GOOD) + continue; /* sliently ignore errors */ + + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + if (opt->type == SANE_TYPE_INT) + { + old_val = GTK_ADJUSTMENT (elem->data)->value; + new_val = word; + GTK_ADJUSTMENT (elem->data)->value = new_val; + } + else + { + old_val = GTK_ADJUSTMENT (elem->data)->value; + new_val = SANE_UNFIX (word); + if (opt->unit == SANE_UNIT_MM) + new_val /= preferences.length_unit; + GTK_ADJUSTMENT (elem->data)->value = new_val; + } + if (old_val != new_val) + gtk_signal_emit_by_name (GTK_OBJECT (elem->data), + "value_changed"); + break; + + case SANE_CONSTRAINT_WORD_LIST: + if (opt->type == SANE_TYPE_INT) + sprintf (str, "%d", word); + else + sprintf (str, "%g", SANE_UNFIX (word)); + /* XXX maybe we should call this only when the value changes... */ + gtk_option_menu_set_history (GTK_OPTION_MENU (elem->widget), + option_menu_lookup (elem->menu, str)); + break; + + default: + break; + } + } +} + +/* Ensure sure the device has up-to-date option values. Except for + vectors, all option values are kept current. Vectors are + downloaded into the device during this call. */ +void +gsg_sync (GSGDialog *dialog) +{ + const SANE_Option_Descriptor *opt; + gfloat val, *vector; + SANE_Word *optval; + int i, j, optlen; + GtkWidget *curve; + + for (i = 1; i < dialog->num_elements; ++i) + { + opt = sane_get_option_descriptor (dialog->dev, i); + if (!SANE_OPTION_IS_ACTIVE (opt->cap)) + continue; + + if (opt->type != SANE_TYPE_INT && + opt->type != SANE_TYPE_FIXED) + continue; + + if (opt->size == sizeof (SANE_Word)) + continue; + + /* ok, we're dealing with an active vector */ + + optlen = opt->size / sizeof (SANE_Word); + optval = alloca (optlen * sizeof (optval[0])); + vector = alloca (optlen * sizeof (vector[0])); + + curve = GTK_GAMMA_CURVE (dialog->element[i].widget)->curve; + gtk_curve_get_vector (GTK_CURVE (curve), optlen, vector); + for (j = 0; j < optlen; ++j) + { + val = vector[j]; + if (opt->type == SANE_TYPE_FIXED) + optval[j] = SANE_FIX (val); + else + optval[j] = val + 0.5; + } + + set_option (dialog, i, optval, SANE_ACTION_SET_VALUE); + } +} + +void +gsg_set_advanced (GSGDialog *dialog, int advanced) +{ + dialog->advanced = advanced; + panel_rebuild (dialog); +} + +void +gsg_set_tooltips (GSGDialog *dialog, int enable) +{ + if (!dialog->tooltips) + return; + + if (enable) + gtk_tooltips_enable (dialog->tooltips); + else + gtk_tooltips_disable (dialog->tooltips); +} + +void +gsg_set_sensitivity (GSGDialog *dialog, int sensitive) +{ + const SANE_Option_Descriptor *opt; + int i; + + for (i = 0; i < dialog->num_elements; ++i) + { + opt = sane_get_option_descriptor (dialog->dev, i); + + if (!SANE_OPTION_IS_ACTIVE (opt->cap) + || opt->type == SANE_TYPE_GROUP + || !dialog->element[i].widget) + continue; + + if (!(opt->cap & SANE_CAP_ALWAYS_SETTABLE)) + gtk_widget_set_sensitive (dialog->element[i].widget, sensitive); + } +} + +void +gsg_destroy_dialog (GSGDialog * dialog) +{ + SANE_Handle dev = dialog->dev; + + panel_destroy (dialog); + free ((void *) dialog->dev_name); + free (dialog->element); + free (dialog); + + sane_close (dev); +} diff --git a/src/gtkglue.h b/src/gtkglue.h new file mode 100644 index 0000000..f7063fc --- /dev/null +++ b/src/gtkglue.h @@ -0,0 +1,119 @@ +#ifndef gtkglue_h +#define gtkglue_h + +#include + +#include + +#include +#include + +struct GSGDialog; + +typedef void (*GSGCallback) (struct GSGDialog *dialog, void *arg); + +typedef enum + { + GSG_TL_X, /* top-left x */ + GSG_TL_Y, /* top-left y */ + GSG_BR_X, /* bottom-right x */ + GSG_BR_Y /* bottom-right y */ + } +GSGCornerCoordinates; + +typedef struct + { + /* The option number of the well-known options. Each of these may + be -1 in case the backend doesn't define the respective option. */ + int preview; + int dpi; + int coord[4]; + } +GSGWellKnownOptions; + +typedef struct + { + gchar *label; + struct GSGDialogElement *elem; + gint index; + } +GSGMenuItem; + +typedef struct GSGDialogElement + { + struct GSGDialog *dialog; /* wasteful, but is there a better solution? */ + GtkWidget *automatic; /* auto button for options that support this */ + GtkWidget *widget; + GtkObject *data; + int menu_size; /* # of items in menu (if any) */ + GSGMenuItem *menu; + } +GSGDialogElement; + +typedef struct GSGDialog + { + GtkWidget *window; + GtkWidget *main_hbox; + GtkWidget *advanced_vbox; + GtkTooltips *tooltips; + GdkColor tooltips_fg; + GdkColor tooltips_bg; + SANE_Handle *dev; + const char *dev_name; + GSGWellKnownOptions well_known; + int num_elements; + GSGDialogElement *element; + gint idle_id; + u_int rebuild : 1; + u_int advanced : 1; + /* This callback gets invoked whenever the backend notifies us + that the option descriptors have changed. */ + GSGCallback option_reload_callback; + void *option_reload_arg; + /* This callback gets invoked whenever the backend notifies us + that the parameters have changed. */ + GSGCallback param_change_callback; + void *param_change_arg; + } +GSGDialog; + + +extern int gsg_message_dialog_active; + +/* Construct the path and return it in filename_ret (this buffer must + be at least max_len bytes long). The path is constructed as + follows: + + ~/.sane/${PROG_NAME}/${PREFIX}${DEV_NAME}${POSTFIX} + + If PROG_NAME is NULL, an empty string is used and the leading slash + is removed. On success, 0 is returned, on error a negative number and + ERRNO is set to the appropriate value. */ +extern int gsg_make_path (size_t max_len, char *filename_ret, + const char *prog_name, + const char *prefix, const char *dev_name, + const char *postfix); + +extern void gsg_message (gchar *title, gchar * message); +extern void gsg_error (gchar * error_message); +extern void gsg_warning (gchar * warning_message); +extern int gsg_get_filename (const char *label, const char *default_name, + size_t max_len, char *filename); + +extern GSGDialog *gsg_create_dialog (GtkWidget *window, + const char *device_name, + GSGCallback option_reload_callback, + void *option_reload_arg, + GSGCallback param_callback, + void *param_arg); +extern void gsg_sync (GSGDialog *dialog); +extern void gsg_refresh_dialog (GSGDialog *dialog); +extern void gsg_update_scan_window (GSGDialog *dialog); +extern void gsg_set_advanced (GSGDialog *dialog, int advanced); +extern void gsg_set_tooltips (GSGDialog *dialog, int enable); +extern void gsg_set_sensitivity (GSGDialog *dialog, int sensitive); +extern void gsg_destroy_dialog (GSGDialog * dialog); + +#define gsg_dialog_get_device(dialog) ((dialog)->dev) + +#endif /* gtkglue_h */ diff --git a/src/preferences.c b/src/preferences.c new file mode 100644 index 0000000..1e4b21d --- /dev/null +++ b/src/preferences.c @@ -0,0 +1,181 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include +#include +#include "../include/sane/sanei.h" +#include "../include/sane/sanei_wire.h" +#include "../include/sane/sanei_codec_ascii.h" + +#define POFFSET(field) ((char *) &((Preferences *) 0)->field - (char *) 0) +#define PFIELD(p,offset,type) (*((type *)(((char *)(p)) + (offset)))) + +Preferences preferences = + { + 0, /* no preferred device (must be 0 or malloced!) */ + 0, /* no default filename */ + 0, /* advanced user */ + 1, /* tooltips enabled */ + 10.0, /* length unit */ + 1, /* preserve_preview */ + 0, /* preview_own_cmap */ + 1.0 /* preview_gamma */ + }; + +static void w_string (Wire *w, Preferences *p, long offset); +static void w_double (Wire *w, Preferences *p, long offset); +static void w_int (Wire *w, Preferences *p, long offset); + +static struct + { + SANE_String name; + void (*codec) (Wire *w, Preferences *p, long offset); + long offset; + } +desc[] = + { + {"device", w_string, POFFSET(device)}, + {"filename", w_string, POFFSET(filename)}, + {"advanced", w_int, POFFSET(advanced)}, + {"tool-tips", w_int, POFFSET(tooltips_enabled)}, + {"length-unit", w_double, POFFSET(length_unit)}, + {"preserve-preview", w_int, POFFSET(preserve_preview)}, + {"preview-own-cmap", w_int, POFFSET(preview_own_cmap)}, + {"preview-gamma", w_double, POFFSET(preview_gamma)}, + }; + +static void +w_string (Wire *w, Preferences *p, long offset) +{ + SANE_String string; + + if (w->direction == WIRE_ENCODE) + string = PFIELD (p, offset, char *); + + sanei_w_string (w, &string); + + if (w->direction == WIRE_DECODE) + { + if (w->status == 0) + { + const char **field; + + field = &PFIELD (p, offset, const char *); + if (*field) + free ((char *) *field); + *field = string ? strdup (string) : 0; + } + sanei_w_free (w, (WireCodecFunc) sanei_w_string, &string); + } +} + +static void +w_double (Wire *w, Preferences *p, long offset) +{ + SANE_Word word; + + if (w->direction == WIRE_ENCODE) + word = SANE_FIX (PFIELD (p, offset, double)); + + sanei_w_word (w, &word); + + if (w->direction == WIRE_DECODE) + { + if (w->status == 0) + PFIELD (p, offset, double) = SANE_UNFIX (word); + sanei_w_free (w, (WireCodecFunc) sanei_w_word, &word); + } +} + +static void +w_int (Wire *w, Preferences *p, long offset) +{ + SANE_Word word; + + if (w->direction == WIRE_ENCODE) + word = PFIELD (p, offset, int); + + sanei_w_word (w, &word); + + if (w->direction == WIRE_DECODE) + { + if (w->status == 0) + PFIELD (p, offset, int) = word; + sanei_w_free (w, (WireCodecFunc) sanei_w_word, &word); + } +} + +void +preferences_save (int fd) +{ + Wire w; + int i; + + w.io.fd = fd; + w.io.read = read; + w.io.write = write; + sanei_w_init (&w, sanei_codec_ascii_init); + sanei_w_set_dir (&w, WIRE_ENCODE); + + for (i = 0; i < NELEMS (desc); ++i) + { + sanei_w_string (&w, &desc[i].name); + (*desc[i].codec) (&w, &preferences, desc[i].offset); + } + + sanei_w_set_dir (&w, WIRE_DECODE); /* flush it out */ +} + +void +preferences_restore (int fd) +{ + SANE_String name; + Wire w; + int i; + + w.io.fd = fd; + w.io.read = read; + w.io.write = write; + sanei_w_init (&w, sanei_codec_ascii_init); + sanei_w_set_dir (&w, WIRE_DECODE); + + while (1) + { + sanei_w_space (&w, 3); + if (w.status) + return; + + sanei_w_string (&w, &name); + if (w.status || !name) + return; + + for (i = 0; i < NELEMS (desc); ++i) + { + if (strcmp (name, desc[i].name) == 0) + { + (*desc[i].codec) (&w, &preferences, desc[i].offset); + break; + } + } + } +} diff --git a/src/preferences.h b/src/preferences.h new file mode 100644 index 0000000..1caa62b --- /dev/null +++ b/src/preferences.h @@ -0,0 +1,24 @@ +#ifndef preferences_h +#define preferences_h + +#include + +typedef struct + { + const char *device; /* name of preferred device (or NULL) */ + const char *filename; /* default filename */ + int advanced; /* advanced user? */ + int tooltips_enabled; /* should tooltips be disabled? */ + double length_unit; /* 1.0==mm, 10.0==cm, 25.4==inches, etc. */ + int preserve_preview; /* save/restore preview image(s)? */ + int preview_own_cmap; /* install colormap for preview */ + double preview_gamma; /* gamma value for previews */ + } +Preferences; + +extern Preferences preferences; + +extern void preferences_save (int fd); +extern void preferences_restore (int fd); + +#endif /* preferences_h */ diff --git a/src/preview.c b/src/preview.c new file mode 100644 index 0000000..7b2dae1 --- /dev/null +++ b/src/preview.c @@ -0,0 +1,1349 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang and Tristan Tarrant + This file is part of the SANE package. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + The preview strategy is as follows: + + 1) A preview always acquires an image that covers the entire + scan surface. This is necessary so the user can see not + only what is, but also what isn't selected. + + 2) The preview must be zoomable so the user can precisely pick + the selection area even for small scans on a large scan + surface. The user also should have the option of resizing + the preview window. + + 3) We let the user/backend pick whether a preview is in color, + grayscale, lineart or what not. The only options that the + preview may (temporarily) modify are: + + - resolution (set so the preview fills the window) + - scan area options (top-left corner, bottom-right corner) + - preview option (to let the backend know we're doing a preview) + + 4) The size of the scan surface is determined based on the constraints + of the four corner coordinates. Missing constraints are replaced + by +/-INF as appropriate (-INF form top-left, +INF for bottom-right + coords). + + 5) The size of the preview window is determined based on the scan + surface size: + + If the surface area is specified in pixels and if that size + fits on the screen, we use that size. In all other cases, + we make the window of a size so that neither the width nor + the height is bigger than some fraction of the screen-size + while preserving the aspect ratio (a surface width or height + of INF implies an aspect ratio of 1). + + 6) Given the preview window size and the scan surface size, we + select the resolution so the acquired preview image just fits + in the preview window. The resulting resolution may be out + of range in which case we pick the minum/maximum if there is + a range or word-list constraint or a default value if there is + no such constraint. + + 7) Once a preview image has been acquired, we know the size of the + preview image (in pixels). An initial scale factor is chosen + so the image fits into the preview window. + + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + +/* Anything bigger than 2G will do, since SANE coordinates are 32 bit + values. */ +#define INF 5.0e9 + +#define MM_PER_INCH 25.4 + +/* Cut fp conversion routines some slack: */ +#define GROSSLY_DIFFERENT(f1,f2) (fabs ((f1) - (f2)) > 1e-3) + +#ifdef __alpha__ + /* This seems to be necessary for at least some XFree86 3.1.2 + servers. It's known to be necessary for the XF86_TGA server for + Linux/Alpha. Fortunately, it's no great loss so we turn this on + by default for now. */ +# define XSERVER_WITH_BUGGY_VISUALS +#endif + +/* forward declarations */ +static void scan_start (Preview *p); +static void scan_done (Preview *p); + +static void +draw_rect (GdkWindow *win, GdkGC *gc, int coord[4]) +{ + gint x, y, w, h; + + x = coord[0]; + y = coord[1]; + w = coord[2] - x; + h = coord[3] - y; + if (w < 0) + { + x = coord[2]; + w = -w; + } + if (h < 0) + { + y = coord[3]; + h = -h; + } + gdk_draw_rectangle (win, gc, FALSE, x, y, w + 1, h + 1); +} + +static void +draw_selection (Preview *p) +{ + if (!p->gc) + /* window isn't mapped yet */ + return; + + if (p->previous_selection.active) + draw_rect (p->window->window, p->gc, p->previous_selection.coord); + + if (p->selection.active) + draw_rect (p->window->window, p->gc, p->selection.coord); + + p->previous_selection = p->selection; +} + +static void +update_selection (Preview *p) +{ + float min, max, normal, dev_selection[4]; + const SANE_Option_Descriptor *opt; + SANE_Status status; + SANE_Word val; + int i, optnum; + + p->previous_selection = p->selection; + + memcpy (dev_selection, p->surface, sizeof (dev_selection)); + for (i = 0; i < 4; ++i) + { + optnum = p->dialog->well_known.coord[i]; + if (optnum > 0) + { + opt = sane_get_option_descriptor (p->dialog->dev, optnum); + status = sane_control_option (p->dialog->dev, optnum, + SANE_ACTION_GET_VALUE, &val, 0); + if (status != SANE_STATUS_GOOD) + continue; + if (opt->type == SANE_TYPE_FIXED) + dev_selection[i] = SANE_UNFIX (val); + else + dev_selection[i] = val; + } + } + for (i = 0; i < 2; ++i) + { + min = p->surface[i]; + if (min <= -INF) + min = 0.0; + max = p->surface[i + 2]; + if (max >= INF) + max = p->preview_width; + + normal = ((i == 0) ? p->preview_width : p->preview_height) - 1; + normal /= (max - min); + p->selection.active = TRUE; + p->selection.coord[i] = ((dev_selection[i] - min)*normal) + 0.5; + p->selection.coord[i + 2] = ((dev_selection[i + 2] - min)*normal) + 0.5; + if (p->selection.coord[i + 2] < p->selection.coord[i]) + p->selection.coord[i + 2] = p->selection.coord[i]; + } + draw_selection (p); +} + +static void +get_image_scale (Preview *p, float *xscalep, float *yscalep) +{ + float xscale, yscale; + + if (p->image_width == 0) + xscale = 1.0; + else + { + xscale = p->image_width/(float) p->preview_width; + if (p->image_height > 0 && p->preview_height*xscale < p->image_height) + xscale = p->image_height/(float) p->preview_height; + } + yscale = xscale; + + if (p->surface_unit == SANE_UNIT_PIXEL + && p->image_width <= p->preview_width + && p->image_height <= p->preview_height) + { + float swidth, sheight; + + assert (p->surface_type == SANE_TYPE_INT); + swidth = (p->surface[GSG_BR_X] - p->surface[GSG_TL_X] + 1); + sheight = (p->surface[GSG_BR_Y] - p->surface[GSG_TL_Y] + 1); + xscale = 1.0; + yscale = 1.0; + if (p->image_width > 0 && swidth < INF) + xscale = p->image_width/swidth; + if (p->image_height > 0 && sheight < INF) + yscale = p->image_height/sheight; + } + *xscalep = xscale; + *yscalep = yscale; +} + +static void +paint_image (Preview *p) +{ + float xscale, yscale, src_x, src_y; + int dst_x, dst_y, height, x, y, src_offset; + gint gwidth, gheight; + + gwidth = p->preview_width; + gheight = p->preview_height; + + get_image_scale (p, &xscale, &yscale); + + memset (p->preview_row, 0xff, 3*gwidth); + + /* don't draw last line unless it's complete: */ + height = p->image_y; + if (p->image_x == 0 && height < p->image_height) + ++height; + + /* for now, use simple nearest-neighbor interpolation: */ + src_offset = 0; + src_x = src_y = 0.0; + for (dst_y = 0; dst_y < gheight; ++dst_y) + { + y = (int) (src_y + 0.5); + if (y >= height) + break; + src_offset = y*3*p->image_width; + + if (p->image_data) + for (dst_x = 0; dst_x < gwidth; ++dst_x) + { + x = (int) (src_x + 0.5); + if (x >= p->image_width) + break; + + p->preview_row[3*dst_x + 0] = p->image_data[src_offset + 3*x + 0]; + p->preview_row[3*dst_x + 1] = p->image_data[src_offset + 3*x + 1]; + p->preview_row[3*dst_x + 2] = p->image_data[src_offset + 3*x + 2]; + src_x += xscale; + } + gtk_preview_draw_row (GTK_PREVIEW (p->window), p->preview_row, + 0, dst_y, gwidth); + src_x = 0.0; + src_y += yscale; + } +} + +static void +display_partial_image (Preview *p) +{ + paint_image (p); + + if (GTK_WIDGET_DRAWABLE (p->window)) + { + GtkPreview *preview = GTK_PREVIEW (p->window); + int src_x, src_y; + + src_x = (p->window->allocation.width - preview->buffer_width)/2; + src_y = (p->window->allocation.height - preview->buffer_height)/2; + gtk_preview_put (preview, p->window->window, p->window->style->black_gc, + src_x, src_y, + 0, 0, p->preview_width, p->preview_height); + } +} + +static void +display_maybe (Preview *p) +{ + time_t now; + + time (&now); + if (now > p->image_last_time_updated) + { + p->image_last_time_updated = now; + display_partial_image (p); + } +} + +static void +display_image (Preview *p) +{ + if (p->params.lines <= 0 && p->image_y < p->image_height) + { + p->image_height = p->image_y; + p->image_data = realloc (p->image_data, + 3*p->image_width*p->image_height); + assert (p->image_data); + } + display_partial_image (p); + scan_done (p); +} + +static void +preview_area_resize (GtkWidget *widget) +{ + float min_x, max_x, min_y, max_y, xscale, yscale, f; + Preview *p; + + p = gtk_object_get_data (GTK_OBJECT (widget), "PreviewPointer"); + + p->preview_width = widget->allocation.width; + p->preview_height = widget->allocation.height; + + if (p->preview_row) + p->preview_row = realloc (p->preview_row, 3*p->preview_width); + else + p->preview_row = malloc (3*p->preview_width); + + /* set the ruler ranges: */ + + min_x = p->surface[GSG_TL_X]; + if (min_x <= -INF) + min_x = 0.0; + + max_x = p->surface[GSG_BR_X]; + if (max_x >= INF) + max_x = p->preview_width - 1; + + min_y = p->surface[GSG_TL_Y]; + if (min_y <= -INF) + min_y = 0.0; + + max_y = p->surface[GSG_BR_Y]; + if (max_y >= INF) + max_y = p->preview_height - 1; + + /* convert mm to inches if that's what the user wants: */ + + if (p->surface_unit == SANE_UNIT_MM) + { + double factor = 1.0/preferences.length_unit; + min_x *= factor; max_x *= factor; min_y *= factor; max_y *= factor; + } + + get_image_scale (p, &xscale, &yscale); + + if (p->surface_unit == SANE_UNIT_PIXEL) + f = 1.0/xscale; + else if (p->image_width) + f = xscale*p->preview_width/p->image_width; + else + f = 1.0; + gtk_ruler_set_range (GTK_RULER (p->hruler), f*min_x, f*max_x, f*min_x, + /* max_size */ 20); + + if (p->surface_unit == SANE_UNIT_PIXEL) + f = 1.0/yscale; + else if (p->image_height) + f = yscale*p->preview_height/p->image_height; + else + f = 1.0; + gtk_ruler_set_range (GTK_RULER (p->vruler), f*min_y, f*max_y, f*min_y, + /* max_size */ 20); + + paint_image (p); + update_selection (p); +} + +static void +get_bounds (const SANE_Option_Descriptor *opt, float *minp, float *maxp) +{ + float min, max; + int i; + + min = -INF; + max = INF; + switch (opt->constraint_type) + { + case SANE_CONSTRAINT_RANGE: + min = opt->constraint.range->min; + max = opt->constraint.range->max; + break; + + case SANE_CONSTRAINT_WORD_LIST: + min = INF; + max = -INF; + for (i = 1; i <= opt->constraint.word_list[0]; ++i) + { + if (opt->constraint.word_list[i] < min) + min = opt->constraint.word_list[i]; + if (opt->constraint.word_list[i] > max) + max = opt->constraint.word_list[i]; + } + break; + + default: + break; + } + if (opt->type == SANE_TYPE_FIXED) + { + if (min > -INF && min < INF) + min = SANE_UNFIX (min); + if (max > -INF && max < INF) + max = SANE_UNFIX (max); + } + *minp = min; + *maxp = max; +} + +static void +save_option (Preview *p, int option, SANE_Word *save_loc, int *valid) +{ + SANE_Status status; + + if (option <= 0) + { + *valid = 0; + return; + } + status = sane_control_option (p->dialog->dev, option, SANE_ACTION_GET_VALUE, + save_loc, 0); + *valid = (status == SANE_STATUS_GOOD); +} + +static void +restore_option (Preview *p, int option, SANE_Word saved_value, int valid) +{ + const SANE_Option_Descriptor *opt; + SANE_Status status; + SANE_Handle dev; + + if (!valid) + return; + + dev = p->dialog->dev; + status = sane_control_option (dev, option, SANE_ACTION_SET_VALUE, + &saved_value, 0); + if (status != SANE_STATUS_GOOD) + { + char buf[256]; + opt = sane_get_option_descriptor (dev, option); + snprintf (buf, sizeof (buf), "Failed restore value of option %s: %s.", + opt->name, sane_strstatus (status)); + gsg_error (buf); + } +} + +static void +set_option_float (Preview *p, int option, float value) +{ + const SANE_Option_Descriptor *opt; + SANE_Handle dev; + SANE_Word word; + + if (option <= 0 || value <= -INF || value >= INF) + return; + + dev = p->dialog->dev; + opt = sane_get_option_descriptor (dev, option); + if (opt->type == SANE_TYPE_FIXED) + word = SANE_FIX (value) + 0.5; + else + word = value + 0.5; + sane_control_option (dev, option, SANE_ACTION_SET_VALUE, &word, 0); +} + +static void +set_option_bool (Preview *p, int option, SANE_Bool value) +{ + SANE_Handle dev; + + if (option <= 0) + return; + + dev = p->dialog->dev; + sane_control_option (dev, option, SANE_ACTION_SET_VALUE, &value, 0); +} + +static int +increment_image_y (Preview *p) +{ + size_t extra_size, offset; + char buf[256]; + + p->image_x = 0; + ++p->image_y; + if (p->params.lines <= 0 && p->image_y >= p->image_height) + { + offset = 3*p->image_width*p->image_height; + extra_size = 3*32*p->image_width; + p->image_height += 32; + p->image_data = realloc (p->image_data, offset + extra_size); + if (!p->image_data) + { + snprintf (buf, sizeof (buf), + "Failed to reallocate image memory: %s.", + strerror (errno)); + gsg_error (buf); + scan_done (p); + return -1; + } + memset (p->image_data + offset, 0xff, extra_size); + } + return 0; +} + +static void +input_available (gpointer data, gint source, GdkInputCondition cond) +{ + SANE_Status status; + Preview *p = data; + u_char buf[8192]; + SANE_Handle dev; + SANE_Int len; + int i, j; + + dev = p->dialog->dev; + while (1) + { + status = sane_read (dev, buf, sizeof (buf), &len); + if (status != SANE_STATUS_GOOD) + { + if (status == SANE_STATUS_EOF) + { + if (p->params.last_frame) + display_image (p); + else + { + gdk_input_remove (p->input_tag); + p->input_tag = -1; + scan_start (p); + break; + } + } + else + { + snprintf (buf, sizeof (buf), "Error during read: %s.", + sane_strstatus (status)); + gsg_error (buf); + } + scan_done (p); + return; + } + if (!len) + break; /* out of data for now */ + + switch (p->params.format) + { + case SANE_FRAME_RGB: + if (p->params.depth != 8) + goto bad_depth; + + for (i = 0; i < len; ++i) + { + p->image_data[p->image_offset++] = buf[i]; + if (p->image_offset%3 == 0) + { + if (++p->image_x >= p->image_width + && increment_image_y (p) < 0) + return; + } + } + break; + + case SANE_FRAME_GRAY: + switch (p->params.depth) + { + case 1: + for (i = 0; i < len; ++i) + { + u_char mask = buf[i]; + + for (j = 7; j >= 0; --j) + { + u_char gl = (mask & (1 << j)) ? 0x00 : 0xff; + p->image_data[p->image_offset++] = gl; + p->image_data[p->image_offset++] = gl; + p->image_data[p->image_offset++] = gl; + if (++p->image_x >= p->image_width) + { + if (increment_image_y (p) < 0) + return; + break; /* skip padding bits */ + } + } + } + break; + + case 8: + for (i = 0; i < len; ++i) + { + u_char gl = buf[i]; + p->image_data[p->image_offset++] = gl; + p->image_data[p->image_offset++] = gl; + p->image_data[p->image_offset++] = gl; + if (++p->image_x >= p->image_width + && increment_image_y (p) < 0) + return; + } + break; + + default: + goto bad_depth; + } + break; + + case SANE_FRAME_RED: + case SANE_FRAME_GREEN: + case SANE_FRAME_BLUE: + switch (p->params.depth) + { + case 1: + for (i = 0; i < len; ++i) + { + u_char mask = buf[i]; + + for (j = 0; j < 8; ++j) + { + u_char gl = (mask & 1) ? 0xff : 0x00; + mask >>= 1; + p->image_data[p->image_offset++] = gl; + p->image_offset += 3; + if (++p->image_x >= p->image_width + && increment_image_y (p) < 0) + return; + } + } + break; + + case 8: + for (i = 0; i < len; ++i) + { + p->image_data[p->image_offset] = buf[i]; + p->image_offset += 3; + if (++p->image_x >= p->image_width + && increment_image_y (p) < 0) + return; + } + break; + + default: + goto bad_depth; + } + break; + + default: + fprintf (stderr, "preview.input_available: bad frame format %d\n", + p->params.format); + scan_done (p); + return; + } + if (p->input_tag < 0) + { + display_maybe (p); + while (gtk_events_pending ()) + gtk_main_iteration (); + } + } + display_maybe (p); + return; + +bad_depth: + snprintf (buf, sizeof (buf), "Preview cannot handle depth %d.", + p->params.depth); + gsg_error (buf); + scan_done (p); + return; +} + +static void +scan_done (Preview *p) +{ + int i; + + p->scanning = FALSE; + if (p->input_tag >= 0) + { + gdk_input_remove (p->input_tag); + p->input_tag = -1; + } + sane_cancel (p->dialog->dev); + + restore_option (p, p->dialog->well_known.dpi, + p->saved_dpi, p->saved_dpi_valid); + for (i = 0; i < 4; ++i) + restore_option (p, p->dialog->well_known.coord[i], + p->saved_coord[i], p->saved_coord_valid[i]); + set_option_bool (p, p->dialog->well_known.preview, SANE_FALSE); + + gtk_widget_set_sensitive (p->cancel, FALSE); + gsg_set_sensitivity (p->dialog, TRUE); +} + +static void +scan_start (Preview *p) +{ + SANE_Handle dev = p->dialog->dev; + SANE_Status status; + char buf[256]; + int fd, y; + + gtk_widget_set_sensitive (p->cancel, TRUE); + gsg_set_sensitivity (p->dialog, FALSE); + + /* clear old preview: */ + memset (p->preview_row, 0xff, 3*p->preview_width); + for (y = 0; y < p->preview_height; ++y) + gtk_preview_draw_row (GTK_PREVIEW (p->window), p->preview_row, + 0, y, p->preview_width); + + if (p->input_tag >= 0) + { + gdk_input_remove (p->input_tag); + p->input_tag = -1; + } + + gsg_sync (p->dialog); + + status = sane_start (dev); + if (status != SANE_STATUS_GOOD) + { + snprintf (buf, sizeof (buf), + "Failed to start scanner: %s.", sane_strstatus (status)); + gsg_error (buf); + scan_done (p); + return; + } + + status = sane_get_parameters (dev, &p->params); + if (status != SANE_STATUS_GOOD) + { + snprintf (buf, sizeof (buf), + "Failed to obtain parameters: %s.", sane_strstatus (status)); + gsg_error (buf); + scan_done (p); + return; + } + + p->image_offset = p->image_x = p->image_y = 0; + + if (p->params.format >= SANE_FRAME_RED + && p->params.format <= SANE_FRAME_BLUE) + p->image_offset = p->params.format - SANE_FRAME_RED; + + if (!p->image_data || p->params.pixels_per_line != p->image_width + || (p->params.lines >= 0 && p->params.lines != p->image_height)) + { + /* image size changed */ + if (p->image_data) + free (p->image_data); + + p->image_width = p->params.pixels_per_line; + p->image_height = p->params.lines; + if (p->image_height < 0) + p->image_height = 32; /* may have to adjust as we go... */ + + p->image_data = malloc (3*p->image_width*p->image_height); + if (!p->image_data) + { + snprintf (buf, sizeof (buf), + "Failed to allocate image memory: %s.", strerror (errno)); + gsg_error (buf); + scan_done (p); + return; + } + memset (p->image_data, 0xff, 3*p->image_width*p->image_height); + } + + if (p->selection.active) + { + p->previous_selection = p->selection; + p->selection.active = FALSE; + draw_selection (p); + } + p->scanning = TRUE; + + if (sane_set_io_mode (dev, SANE_TRUE) == SANE_STATUS_GOOD + && sane_get_select_fd (dev, &fd) == SANE_STATUS_GOOD) + p->input_tag = gdk_input_add (fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, input_available, p); + else + input_available (p, -1, GDK_INPUT_READ); +} + +static void +establish_selection (Preview *p) +{ + float min, max, normal, dev_selection[4]; + int i; + + memcpy (dev_selection, p->surface, sizeof (dev_selection)); + if (p->selection.active) + for (i = 0; i < 2; ++i) + { + min = p->surface[i]; + if (min <= -INF) + min = 0.0; + max = p->surface[i + 2]; + if (max >= INF) + max = p->preview_width; + + normal = 1.0/(((i == 0) ? p->preview_width : p->preview_height) - 1); + normal *= (max - min); + dev_selection[i] = p->selection.coord[i]*normal + min; + dev_selection[i + 2] = p->selection.coord[i + 2]*normal + min; + } + for (i = 0; i < 4; ++i) + set_option_float (p, p->dialog->well_known.coord[i], dev_selection[i]); + gsg_update_scan_window (p->dialog); + if (p->dialog->param_change_callback) + (*p->dialog->param_change_callback) (p->dialog, + p->dialog->param_change_arg); +} + +static int +make_preview_image_path (Preview *p, size_t filename_size, char *filename) +{ + return gsg_make_path (filename_size, filename, 0, "preview-", + p->dialog->dev_name, ".ppm"); +} + +static void +restore_preview_image (Preview *p) +{ + u_int psurface_type, psurface_unit; + char filename[PATH_MAX]; + int width, height; + float psurface[4]; + size_t nread; + FILE *in; + + /* See whether there is a saved preview and load it if present: */ + + if (make_preview_image_path (p, sizeof (filename), filename) < 0) + return; + + in = fopen (filename, "r"); + if (!in) + return; + + /* Be careful about consuming too many bytes after the final newline + (e.g., consider an image whose first image byte is 13 (`\r'). */ + if (fscanf (in, "P6\n# surface: %g %g %g %g %u %u\n%d %d\n255%*[\n]", + psurface + 0, psurface + 1, psurface + 2, psurface + 3, + &psurface_type, &psurface_unit, + &width, &height) != 8) + return; + + if (GROSSLY_DIFFERENT (psurface[0], p->surface[0]) + || GROSSLY_DIFFERENT (psurface[1], p->surface[1]) + || GROSSLY_DIFFERENT (psurface[2], p->surface[2]) + || GROSSLY_DIFFERENT (psurface[3], p->surface[3]) + || psurface_type != p->surface_type || psurface_unit != p->surface_unit) + /* ignore preview image that was acquired for/with a different surface */ + return; + + p->image_width = width; + p->image_height = height; + p->image_data = malloc (3*width*height); + if (!p->image_data) + return; + + nread = fread (p->image_data, 3, width*height, in); + + p->image_y = nread/width; + p->image_x = nread%width; +} + +/* This is executed _after_ the gtkpreview's expose routine. */ +static gint +expose_handler (GtkWidget *window, GdkEvent *event, gpointer data) +{ + Preview *p = data; + + p->selection.active = FALSE; + update_selection (p); + return FALSE; +} + +static gint +event_handler (GtkWidget *window, GdkEvent *event, gpointer data) +{ + Preview *p = data; + int i, tmp; + + if (event->type == GDK_EXPOSE) + { + if (!p->gc) + { + p->gc = gdk_gc_new (p->window->window); + gdk_gc_set_function (p->gc, GDK_INVERT); + gdk_gc_set_line_attributes (p->gc, 1, GDK_LINE_ON_OFF_DASH, + GDK_CAP_BUTT, GDK_JOIN_MITER); + paint_image (p); + } + else + { + p->selection.active = FALSE; + draw_selection (p); + } + } + else if (!p->scanning) + switch (event->type) + { + case GDK_UNMAP: + case GDK_MAP: + break; + + case GDK_BUTTON_PRESS: + p->selection.coord[0] = event->button.x; + p->selection.coord[1] = event->button.y; + p->selection_drag = TRUE; + break; + + case GDK_BUTTON_RELEASE: + if (!p->selection_drag) + break; + p->selection_drag = FALSE; + + p->selection.coord[2] = event->button.x; + p->selection.coord[3] = event->button.y; + p->selection.active = + (p->selection.coord[0] != p->selection.coord[2] + || p->selection.coord[1] != p->selection.coord[3]); + + if (p->selection.active) + { + for (i = 0; i < 2; i += 1) + if (p->selection.coord[i] > p->selection.coord[i + 2]) + { + tmp = p->selection.coord[i]; + p->selection.coord[i] = p->selection.coord[i + 2]; + p->selection.coord[i + 2] = tmp; + } + if (p->selection.coord[0] < 0) + p->selection.coord[0] = 0; + if (p->selection.coord[1] < 0) + p->selection.coord[1] = 0; + if (p->selection.coord[2] >= p->preview_width) + p->selection.coord[2] = p->preview_width - 1; + if (p->selection.coord[3] >= p->preview_height) + p->selection.coord[3] = p->preview_height - 1; + } + draw_selection (p); + establish_selection (p); + break; + + case GDK_MOTION_NOTIFY: + if (p->selection_drag) + { + p->selection.active = TRUE; + p->selection.coord[2] = event->motion.x; + p->selection.coord[3] = event->motion.y; + draw_selection (p); + } + break; + + default: +#if 0 + fprintf (stderr, "event_handler: unhandled event type %d\n", + event->type); +#endif + break; + } + return FALSE; +} + +static void +start_button_clicked (GtkWidget *widget, gpointer data) +{ + preview_scan (data); +} + +static void +cancel_button_clicked (GtkWidget *widget, gpointer data) +{ + scan_done (data); +} + +static void +top_destroyed (GtkWidget *widget, gpointer call_data) +{ + Preview *p = call_data; + + p->top = NULL; +} + +Preview * +preview_new (GSGDialog *dialog) +{ + static int first_time = 1; + GtkWidget *table, *frame, *button; + GtkSignalFunc signal_func; + GtkWidgetClass *class; + GtkBox *vbox, *hbox; + Preview *p; + + p = malloc (sizeof (*p)); + if (!p) + return 0; + memset (p, 0, sizeof (*p)); + + p->dialog = dialog; + p->input_tag = -1; + + if (first_time) + { + first_time = 0; + gtk_preview_set_gamma (preferences.preview_gamma); + gtk_preview_set_install_cmap (preferences.preview_own_cmap); + } + +#ifndef XSERVER_WITH_BUGGY_VISUALS + gtk_widget_push_visual (gtk_preview_get_visual ()); +#endif + gtk_widget_push_colormap (gtk_preview_get_cmap ()); + + p->top = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (p->top), "destroy", + GTK_SIGNAL_FUNC (top_destroyed), p); + gtk_window_set_title (GTK_WINDOW (p->top), "xscan preview"); + vbox = GTK_BOX (GTK_DIALOG (p->top)->vbox); + hbox = GTK_BOX (GTK_DIALOG (p->top)->action_area); + + /* construct the preview area (table with sliders & preview window) */ + table = gtk_table_new (2, 2, /* homogeneous */ FALSE); + gtk_table_set_col_spacing (GTK_TABLE (table), 0, 1); + gtk_table_set_row_spacing (GTK_TABLE (table), 0, 1); + gtk_container_border_width (GTK_CONTAINER (table), 2); + gtk_box_pack_start (vbox, table, /* expand */ TRUE, /* fill */ TRUE, + /* padding */ 0); + + /* the empty box in the top-left corner */ + frame = gtk_frame_new (/* label */ 0); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT); + gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1, + GTK_FILL, GTK_FILL, 0, 0); + + /* the horizontal ruler */ + p->hruler = gtk_hruler_new (); + gtk_table_attach (GTK_TABLE (table), p->hruler, 1, 2, 0, 1, + GTK_FILL, 0, 0, 0); + + /* the vertical ruler */ + p->vruler = gtk_vruler_new (); + gtk_table_attach (GTK_TABLE (table), p->vruler, 0, 1, 1, 2, 0, + GTK_FILL, 0, 0); + + /* the preview area */ + + p->window = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_preview_set_expand (GTK_PREVIEW (p->window), TRUE); + gtk_widget_set_events (p->window, + GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK); + gtk_signal_connect (GTK_OBJECT (p->window), "event", + (GtkSignalFunc) event_handler, p); + gtk_signal_connect_after (GTK_OBJECT (p->window), "expose_event", + (GtkSignalFunc) expose_handler, p); + gtk_signal_connect_after (GTK_OBJECT (p->window), "size_allocate", + (GtkSignalFunc) preview_area_resize, 0); + gtk_object_set_data (GTK_OBJECT (p->window), "PreviewPointer", p); + + /* Connect the motion-notify events of the preview area with the + rulers. Nifty stuff! */ + + class = GTK_WIDGET_CLASS (GTK_OBJECT (p->hruler)->klass); + signal_func = (GtkSignalFunc) class->motion_notify_event; + gtk_signal_connect_object (GTK_OBJECT (p->window), "motion_notify_event", + signal_func, GTK_OBJECT (p->hruler)); + + class = GTK_WIDGET_CLASS (GTK_OBJECT (p->vruler)->klass); + signal_func = (GtkSignalFunc) class->motion_notify_event; + gtk_signal_connect_object (GTK_OBJECT (p->window), "motion_notify_event", + signal_func, GTK_OBJECT (p->vruler)); + + p->viewport = gtk_frame_new (/* label */ 0); + gtk_frame_set_shadow_type (GTK_FRAME (p->viewport), GTK_SHADOW_IN); + gtk_container_add (GTK_CONTAINER (p->viewport), p->window); + + gtk_table_attach (GTK_TABLE (table), p->viewport, 1, 2, 1, 2, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0); + + preview_update (p); + + /* fill in action area: */ + + /* Start button */ + button = gtk_button_new_with_label ("Acquire Preview"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) start_button_clicked, p); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + /* Cancel button */ + p->cancel = gtk_button_new_with_label ("Cancel Preview"); + gtk_signal_connect (GTK_OBJECT (p->cancel), "clicked", + (GtkSignalFunc) cancel_button_clicked, p); + gtk_box_pack_start (GTK_BOX (hbox), p->cancel, TRUE, TRUE, 0); + gtk_widget_set_sensitive (p->cancel, FALSE); + + gtk_widget_show (p->cancel); + gtk_widget_show (p->viewport); + gtk_widget_show (p->window); + gtk_widget_show (p->hruler); + gtk_widget_show (p->vruler); + gtk_widget_show (frame); + gtk_widget_show (table); + gtk_widget_show (p->top); + + gtk_widget_pop_colormap (); +#ifndef XSERVER_WITH_BUGGY_VISUALS + gtk_widget_pop_visual (); +#endif + return p; +} + +void +preview_update (Preview *p) +{ + float val, width, height, max_width, max_height; + const SANE_Option_Descriptor *opt; + int i, surface_changed; + SANE_Value_Type type; + SANE_Unit unit; + float min, max; + + surface_changed = 0; + unit = SANE_UNIT_PIXEL; + type = SANE_TYPE_INT; + for (i = 0; i < 4; ++i) + { + val = (i & 2) ? INF : -INF; + if (p->dialog->well_known.coord[i] > 0) + { + opt = sane_get_option_descriptor (p->dialog->dev, + p->dialog->well_known.coord[i]); + assert (opt->unit == SANE_UNIT_PIXEL || opt->unit == SANE_UNIT_MM); + unit = opt->unit; + type = opt->type; + + get_bounds (opt, &min, &max); + if (i & 2) + val = max; + else + val = min; + } + if (p->surface[i] != val) + { + surface_changed = 1; + p->surface[i] = val; + } + } + if (p->surface_unit != unit) + { + surface_changed = 1; + p->surface_unit = unit; + } + if (p->surface_type != type) + { + surface_changed = 1; + p->surface_type = type; + } + if (surface_changed && p->image_data) + { + free (p->image_data); + p->image_data = 0; + p->image_width = 0; + p->image_height = 0; + } + + /* guess the initial preview window size: */ + + width = p->surface[GSG_BR_X] - p->surface[GSG_TL_X]; + height = p->surface[GSG_BR_Y] - p->surface[GSG_TL_Y]; + if (p->surface_type == SANE_TYPE_INT) + { + width += 1.0; + height += 1.0; + } + else + { + width += SANE_UNFIX (1.0); + height += SANE_UNFIX (1.0); + } + + assert (width > 0.0 && height > 0.0); + + if (width >= INF || height >= INF) + p->aspect = 1.0; + else + p->aspect = width/height; + + max_width = 0.5*gdk_screen_width (); + max_height = 0.5*gdk_screen_height (); + + if (p->surface_unit != SANE_UNIT_PIXEL) + { + width = max_width; + height = max_height; + } + else + { + if (width > max_width) + width = max_width; + + if (height > max_height) + height = max_height; + } + + /* re-adjust so we maintain aspect without exceeding max size: */ + if (width/height != p->aspect) + { + if (p->aspect > 1.0) + height = width/p->aspect; + else + width = height*p->aspect; + } + + p->preview_width = width + 0.5; + p->preview_height = height + 0.5; + if (surface_changed) + { + gtk_widget_set_usize (GTK_WIDGET (p->window), + p->preview_width, p->preview_height); + if (GTK_WIDGET_DRAWABLE (p->window)) + preview_area_resize (p->window); + + if (preferences.preserve_preview) + restore_preview_image (p); + } + update_selection (p); +} + +void +preview_scan (Preview *p) +{ + float min, max, swidth, sheight, width, height, dpi = 0; + const SANE_Option_Descriptor *opt; + gint gwidth, gheight; + int i; + + save_option (p, p->dialog->well_known.dpi, + &p->saved_dpi, &p->saved_dpi_valid); + for (i = 0; i < 4; ++i) + save_option (p, p->dialog->well_known.coord[i], + &p->saved_coord[i], p->saved_coord_valid + i); + + /* determine dpi, if necessary: */ + + if (p->dialog->well_known.dpi > 0) + { + opt = sane_get_option_descriptor (p->dialog->dev, + p->dialog->well_known.dpi); + + gwidth = p->preview_width; + gheight = p->preview_height; + + height = gheight; + width = height*p->aspect; + if (width > gwidth) + { + width = gwidth; + height = width/p->aspect; + } + + swidth = (p->surface[GSG_BR_X] - p->surface[GSG_TL_X]); + if (swidth < INF) + dpi = MM_PER_INCH*width/swidth; + else + { + sheight = (p->surface[GSG_BR_Y] - p->surface[GSG_TL_Y]); + if (sheight < INF) + dpi = MM_PER_INCH*height/sheight; + else + dpi = 18.0; + } + get_bounds (opt, &min, &max); + if (dpi < min) + dpi = min; + if (dpi > max) + dpi = max; + + set_option_float (p, p->dialog->well_known.dpi, dpi); + } + + /* set the scan window (necessary since backends may default to + non-maximum size): */ + for (i = 0; i < 4; ++i) + set_option_float (p, p->dialog->well_known.coord[i], p->surface[i]); + set_option_bool (p, p->dialog->well_known.preview, SANE_TRUE); + + /* OK, all set to go */ + scan_start (p); +} + +void +preview_destroy (Preview *p) +{ + char filename[PATH_MAX]; + FILE *out; + + if (p->scanning) + scan_done (p); /* don't save partial window */ + else if (preferences.preserve_preview && p->image_data + && make_preview_image_path (p, sizeof (filename), filename) >= 0) + { + /* save preview image */ + out = fopen (filename, "w"); + if (out) + { + /* always save it as a PPM image: */ + fprintf (out, "P6\n# surface: %g %g %g %g %u %u\n%d %d\n255\n", + p->surface[0], p->surface[1], p->surface[2], p->surface[3], + p->surface_type, p->surface_unit, + p->image_width, p->image_height); + fwrite (p->image_data, 3, p->image_width*p->image_height, out); + fclose (out); + } + } + if (p->image_data) + free (p->image_data); + if (p->preview_row) + free (p->preview_row); + if (p->gc) + gdk_gc_destroy (p->gc); + if (p->top) + gtk_widget_destroy (p->top); + free (p); +} diff --git a/src/preview.h b/src/preview.h new file mode 100644 index 0000000..e66bed3 --- /dev/null +++ b/src/preview.h @@ -0,0 +1,86 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 1997 David Mosberger-Tang + This file is part of the SANE package. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef preview_h +#define preview_h + +#include + +#include +#include + +typedef struct + { + GSGDialog *dialog; /* the dialog for this preview */ + + SANE_Value_Type surface_type; + SANE_Unit surface_unit; + float surface[4]; /* the corners of the scan surface (device coords) */ + float aspect; /* the aspect ratio of the scan surface */ + + int saved_dpi_valid; + SANE_Word saved_dpi; + int saved_coord_valid[4]; + SANE_Word saved_coord[4]; + + /* desired/user-selected preview-window size: */ + int preview_width; + int preview_height; + u_char *preview_row; + + int scanning; + time_t image_last_time_updated; + gint input_tag; + SANE_Parameters params; + int image_offset; + int image_x; + int image_y; + int image_width; + int image_height; + u_char *image_data; /* 3 * image_width * image_height bytes */ + + GdkGC *gc; + int selection_drag; + struct + { + int active; + int coord[4]; + } + selection, previous_selection; + + GtkWidget *top; /* top-level widget */ + GtkWidget *hruler; + GtkWidget *vruler; + GtkWidget *viewport; + GtkWidget *window; /* the preview window */ + GtkWidget *cancel; /* the cancel button */ + } +Preview; + +/* Create a new preview based on the info in DIALOG. */ +extern Preview *preview_new (GSGDialog *dialog); + +/* Some of the parameters may have changed---update the preview. */ +extern void preview_update (Preview *p); + +/* Acquire a preview image and display it. */ +extern void preview_scan (Preview *p); + +/* Destroy a preview. */ +extern void preview_destroy (Preview *p); + +#endif /* preview_h */ diff --git a/src/progress.c b/src/progress.c new file mode 100644 index 0000000..3cb2ee2 --- /dev/null +++ b/src/progress.c @@ -0,0 +1,90 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * Hacked (C) 1996 Tristan Tarrant + * + * 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 +#include +#include +#include "progress.h" + +static const int progress_x = 5; +static const int progress_y = 5; + +void +progress_cancel (GtkWidget * widget, gpointer data) +{ + Progress_t *p = (Progress_t *) data; + + (*p->callback) (); +} + + +Progress_t * +progress_new (char *title, char *text, + GtkSignalFunc callback, gpointer callback_data) +{ + GtkWidget *button, *label; + GtkBox *vbox, *hbox; + Progress_t *p; + + p = (Progress_t *) malloc (sizeof (Progress_t)); + p->callback = callback; + + p->shell = gtk_dialog_new (); + gtk_widget_set_uposition (p->shell, progress_x, progress_y); + gtk_window_set_title (GTK_WINDOW (p->shell), title); + vbox = GTK_BOX (GTK_DIALOG (p->shell)->vbox); + hbox = GTK_BOX (GTK_DIALOG (p->shell)->action_area); + + gtk_container_border_width (GTK_CONTAINER (vbox), 7); + + label = gtk_label_new (text); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (vbox, label, FALSE, TRUE, 0); + + p->pbar = gtk_progress_bar_new (); + gtk_widget_set_usize (p->pbar, 200, 20); + gtk_box_pack_start (vbox, p->pbar, TRUE, TRUE, 0); + + button = gtk_toggle_button_new_with_label ("Cancel"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) progress_cancel, p); + gtk_box_pack_start (hbox, button, TRUE, TRUE, 0); + + gtk_widget_show (label); + gtk_widget_show (p->pbar); + gtk_widget_show (button); + gtk_widget_show (GTK_WIDGET (p->shell)); + return p; +} + +void +progress_free (Progress_t * p) +{ + if (p) + { + gtk_widget_destroy (p->shell); + free (p); + } +} + +void +progress_update (Progress_t * p, gfloat newval) +{ + if (p) + gtk_progress_bar_update (GTK_PROGRESS_BAR (p->pbar), newval); +} diff --git a/src/progress.h b/src/progress.h new file mode 100644 index 0000000..13a924e --- /dev/null +++ b/src/progress.h @@ -0,0 +1,34 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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. + */ +#ifndef progress_h +#define progress_h + +typedef struct Progress_t + { + GtkSignalFunc callback; + gpointer callback_data; + GtkWidget *shell; + GtkWidget *pbar; + } +Progress_t; + +extern Progress_t *progress_new (char *, char *, GtkSignalFunc, void *); +extern void progress_free (Progress_t *); +extern void progress_update (Progress_t *, gfloat); + +#endif /* progress_h */ diff --git a/src/sane-style.rc b/src/sane-style.rc new file mode 100644 index 0000000..f85259c --- /dev/null +++ b/src/sane-style.rc @@ -0,0 +1,21 @@ +# style [= ] +# { +#